← Back to Upcase

How to properly use :collection :as to make collection partials


(Kevin Lozandier) #1

#The Problem
I’m having a heard time properly creating a collection according the to the Rails Guide documentation and have had to do a workaround for months.

The Problem In Detail

I have a simple model (goal) ith only one attribute (copy) ; It’s partial is straight-forward

#_goal.html.haml

%li= goal.copy 

Based on the Rails documentation, it should be as simple as the following to render a collection view (with or without decorator/helper encapsulation)

#show.html.haml of the model 

- if @goals.any? 
  = render 'goals/goal', collection: @goals,  as: :goal  
- else 
  = "This Project doesn't have goals, or it wasn't applicable for this particular project to have goals."

For some reason, this has not worked for me ever.

What I’ve had to do instead

Instead, I have had to do the following

#shared/goal_list.html.haml 

%ul.large-12.columns
  = render object.goals

And then the following with the model

- if @goals.any? 
  = render 'shared/goal_list', object: @project 
- else 
  = "This project doesn't have goals, or it wasn't applicable for this particular project to have goals."

## While this works, it's a n+1 problem :/ 

With this in mind, what am I doing wrong to the extend I can’t take advantage of the collection syntax for partials?


(Patrik Bóna) #2

When you specify collection as hash option, then you need also to specify partial name, so try this:

= render partial: 'goals/goal', collection: @goals,  as: :goal

This works for me. Also without as: option.


(Joel Quenneville) #3

Rails gives you a nice shorthand for this:

render @goals

This calls to_partial_path on each model to figure out which partial to render. By default, Goal#to_partial_path returns goals/goal.

This technique also works with a heterogeneous collection:

# app/views/users/show.html.erb
# @user.favorites can contain any combination of Article, Comment, and Image objects
<h1><%= @user.name %>'s Favorites</h1>
<%= render @user.favorites %>
  
# app/views/articles/_article.html.erb
<h1><%= article.name %></h1>
<p><%= article.content %></p>
  
# app/views/comments/_comment.html.erb
<div class="comment">
  <em>Last updated: <%= comment.updated_at %></em>
  <p><%= comment.content %></p>
</div>
  
# app/views/images/_image.html.erb
<h1><%= image.title %></h1>
<%= image_tag image.url %>

(Kevin Lozandier) #4

@joelq, @patrikbona: Thanks to the both of you on helping me improve on either approach; I was aware of the convenience of passing in @goals, but somehow made things hard than they needed to be on this occasion.

It was really handy to be informed of render method way of taking options and extra options the way it does than I realized from the documentation; ‘string’ not necessarily passing that.