Рекомендации по отображению разных данных при использовании одних и тех же частей в Rails

Просто вопрос, связанный с лучшими практиками Rails:

Скажем, у нас есть модель Post и Comment. Один и тот же партиал используется для рендеринга публикации как в представлении index, так и в представлении show. Внутри этого партиала есть ссылка на другой партиал, который отображает комментарии.

post_controller.rb

def index
  @posts = Post.all
end

def show
  @post = Post.find(params[:id])
end

_post.html.haml

.post
  = post.content 
  = render 'comments/list', :comments => post.comments

комментарии/_list.html.haml

- comments.each do |c|
    c.comment

Давайте теперь скажем, что для индексного представления поста мы хотим отображать только последние 3 комментария для каждого поста, а в представлении показа мы хотим отобразить все комментарии к посту. Поскольку используется один и тот же фрагмент, мы не можем изменить вызов, чтобы ограничить количество комментариев. Каков наилучший способ добиться этого? В настоящее время я абстрагировал это помощнику, однако он кажется немного изворотливым:

def limited_comments(comments)
  if params[:controller] == 'posts' and params[:action] == 'show'
    comments
  else
    comments.limit(3)
  end
end

Это означает, что _post.html.haml изменяется на чтение

= render 'comments/list', :comments => limited_comments(post.comments)

Это работает, но не похоже на Rails. Я предполагаю, что есть способ с прицелами, но я не могу понять это.


person Christian    schedule 27.02.2013    source источник


Ответы (2)


Я считаю, что @benchwarmer хотел сказать, что лучше передать параметр в _post partial. Прямолинейные @comments не работают, но что-то вроде приведенного ниже кода может:

def index
  @posts = Post.all
  render :partial => @posts, :locals => { :max_comments => 3 }
end

def show
  @post = Post.find(params[:id])
  render :partial => @post, :locals => { :max_comments => false }
end

В post.html.haml:

= render 'comments/list', :comments => limited_comments(post.comments,max_comments)

Ваш помощник:

def limited_comments(comments,max_comments)
  max_comments ? comments.limit(max_comments) : comments
end

Я не компилировал, поэтому вам может понадобиться дополнительная работа с параметрами, которые вы передаете для рендеринга :partial (возможно, вам придется отдельно установить :partial и :object/:collection в этом случае или что-то еще, я не не помню и не пробовал). Но, надеюсь, идея ясна - логическое представление (все комментарии или последние 3) должно быть отделено от пути обработки (какой контроллер/действие). Возможно, позже вы захотите отобразить посты с комментариями, встроенными в еще один список (последние 3 поста для списка пользователей), тогда такое разделение пригодится.

Если вы не хотите раскрывать все свои внутренние логические детали на уровне контроллера, вы также можете сделать что-то вроде:

def index
  @posts = Post.all
  render :partial => @posts, :locals => { :comments_list_type => :short }
end

def show
  @post = Post.find(params[:id])
  render :partial => @post, :locals => { :comments_list_type => :full }
end

Затем в post.html.haml:

= render 'comments/list', :comments => build_comments_list(post.comments,comments_list_type)

Ваш помощник:

def limited_comments(comments,comments_list_type)
  case comments_list_type
    when :short
      comments.limit(3) 
    when :long
      comments.limit(10) 
    when :full
      comments
  end
end
person moonfly    schedule 27.02.2013
comment
Ах, установка этой переменной max_comments имеет гораздо больше смысла. Спасибо за ответ! - person Christian; 28.02.2013
comment
Это хорошо, но вы можете пойти немного дальше и изменить хелпер, чтобы сделать max_comments необязательным аргументом, по умолчанию равным nil. comments.limit(nil) не будет применять ограничение к запросу. Таким образом, вы избавляетесь от условного выражения, и там, где вы должны были передать max_comments как false, вы можете просто опустить аргумент. - person sockmonk; 19.08.2015

Вы можете последние 3 комментария к действию index и назначить его переменной @comments, а для действия show вы можете загрузить все комментарии к этому сообщению. Так становится

def index
  @posts = Post.all
  @comments = Comment.order("created_at desc").limit(3)
end

def show
  @posts = Post.all
  @comments = @post.comments.order("created_at desc").limit(3)
end

В представлении это просто

= render 'comments/list', :comments => @comments
person benchwarmer    schedule 27.02.2013
comment
Спасибо за ответ, однако это просто список всех комментариев в представлении индекса. Мои комментарии привязаны к сообщениям, и я хочу получить последние 3 для каждого отдельного сообщения. Надеюсь, это имеет смысл, и я обновил вопрос, чтобы объяснить это. - person Christian; 27.02.2013