Just a question related to Rails best practices:
Say we have a Post and a Comment model. The same partial is used to render the post on both the index view and the show view. Inside that partial is a reference to another partial that renders the comments.
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
comments/_list.html.haml
- comments.each do |c|
c.comment
Let's now say that for the post index view, we only want to display the last 3 comments for each post, yet on the show view we want to display all comments for the post. Because the same partial is used, we can't edit the call to limit the comments. What's the best way to achieve this? Currently I've abstracted this out to a helper, however it feels a little dodgy:
def limited_comments(comments)
if params[:controller] == 'posts' and params[:action] == 'show'
comments
else
comments.limit(3)
end
end
Which means _post.html.haml is changed to read
= render 'comments/list', :comments => limited_comments(post.comments)
It works, but doesn't feel like the Rails way. I'm guessing there's a way with scopes, but I can't seem to figure it out.
I believe what @benchwarmer wanted to say is that it's better to pass a parameter to _post partial. Straightforward @comments doesn't work, but something like the code below might:
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
In post.html.haml:
= render 'comments/list', :comments => limited_comments(post.comments,max_comments)
Your helper:
def limited_comments(comments,max_comments)
max_comments ? comments.limit(max_comments) : comments
end
I didn't compile, so you may need to further work on parameters that you pass to render :partial (may be you'll have to separately set :partial and :object/:collection in this case, or smth else, I don't remember and didn't try). But I hope, the idea is clear - keep the logical representation (all comments or last 3) separate from processing path (which controller/action). May be you'll later want to display posts with comments embedded in yet another list (last 3 posts for a list of users), then such separation will come handy.
If you don't want to expose all your internal logical details at controller level, you can also do smth like:
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
Then, in post.html.haml:
= render 'comments/list', :comments => build_comments_list(post.comments,comments_list_type)
Your helper:
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