I have this model called Post, idaelly I would love to use just ONE partial + ONE layout to achieve the following.
when rendering a single object, outputs:
%div= post.body
and when rendering a collection, outputs:
%ul
%li= post.body
%li= post.body
%li= post.body
Currently I have a partial posts/post.haml looking like: %li= post.body
and whenever I'm rendering a collection, I would do%ul=render @posts
The problems being:
Although in 90% of my use cases I'm rendering a collection of post, it doesn't make sense for a post partial not to be usable as a stand-alone template.
I thought I could do something like
# view
render partial: 'post', collection: @posts, layout: 'list_of_posts'
# list_of_posts
%ul= yield
# posts/post
%li= post.body
This would solve my first problem IF IT WORKS, but it doesn't. Apparently render_collection does not take the layout option, so it's practically a dead end from what I can find on rendering collection. (Spacer_template could potentially work, but
</li><li>
as a spacer is in no way a good piece of code.. As for my second problem, an easy way out would be rendering everything in divs, but I am really reluctant to do so when things should be in a list. But for the sake of making it work, it's probably the only clean-ish solution. div.list-of-posts > div.post
instead of ul.posts > li
I know I can always do something like
# view - collection
%ul= render @posts, in_list: true
# view - object
= render @post
# posts/post.haml
- post_counter ||= false
- tag = post_counter ? :li : :div
= content_tag tag do
= post.body
but in this case I still need to put a %ul whenever a collection is passed.
Or else I can do something similar but perhaps a tiny bit cleaner:
# view - collection of objects
= render 'posts', posts: @posts
# view - object
= render @post
# posts/posts.haml
%ul
= render post
# posts/post.haml
- post_counter ||= false
- tag = post_counter ? :li : :div
= content_tag tag do
= post.body
This one is the best/cleanest way I can come up with so far, any thoughts?
Add another partial which renders the li
tag and then invokes the regular partial:
app/views/posts/index.html.haml
%ul.posts= render collection: @posts, partial: "posts/post_li"
app/views/posts/_post_li.html.haml
%li= render post
app/views/posts/_post.html.haml
= div_for post do
....
You can have a single partial and inside the partial it can just check to see if the local passed to it is a collection or a single Post object.
# Render calls
render :partial => "posts/display_posts", :locals => {:posts => Post.first}
render :partial => "posts/display_posts", :locals => {:posts => Post.all} # collection
And your partial:
- if posts.is_a? Post # single item
%div= posts.body
- else
%ul
- posts.each do |post|
%li= post.body
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With