1

The title may not have described my question properly, I wasn't sure how to explain what I'm doing without visuals.

I have a set of snags, each snag is connected to a plot (a plot has many snags). Each plot is linked to a development (a development has many plots). Each development is linked to a user (a user has many developments).

I want to return a list of snags that are relevant to each developer.

I currently have the following in my snags controller:

def index
  @developments = Development.accessible_by(current_ability)
                             .where(enable_snagging: true)
  @developments.each do |development|
    @plots = development.plots
    get_snags(@plots)
  end
end

private

def get_snags(plots)
  plots.each do |plot|
    @plot_snags = Snag.where(plot_id: plot.id)
  end
end

And in my view:

<table class="record-list snags">
  <thead>
    <tr>
      <th><%= sortable(@snags, :id) %></th>
    </tr>
  </thead>
  <tbody>
    <% @snags.each do |snag| %>
    <tr data-snag="<%= snag.id %>">
      <td><%= snag.id %></td>
    </tr>
    <% end %>
  </tbody>
</table>

I initially had @snags in place of @plot_snags in the controller, but of course that only returned the last snag / set of snags, rather than all of them.

If I try to create and return a @snags array and add each object in @plot_snags to it (or any other variation of declaring @snags as an array), I get:

undefined method `human_attribute_name' for #<Array:0x007ff5334861d0>

I can't figure out what I'm doing wrong here.

UPDATE

Having looked at it with fresh eyes again today - I couldn't figure out why my join table isn't populating, I will have a look into it again today to get things working 'properly' - it turns out the error I was getting was due to the Sortable interface I was trying to implement in the view. Once I removed the Sortable I was able to populate my snags array and I get the output I was hoping for.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
DevCF
  • 77
  • 5

2 Answers2

0

When you do an each loop inside the controller you end up with the last value asumed by the variable @some_variable_inside_the_loop. That value is what you get in the view.

There are many ways to solve the problem, for example using joins: https://guides.rubyonrails.org/v5.2/active_record_querying.html#joining-tables

This is very basic option, moving loop in the view as nested loop.

Models about:

development has_many :plots
plot has_many :snags

Controller:

def index
  @developments = Development.accessible_by(current_ability).where(enable_snagging: true)
end

View (let's suppose each model has a title attribute, but do whatever you need):

<% @developments.each do |development| %>
  <%= development.title %>
  <% development.plots.each do |plot| %>
    <%= plot.title %>
    <% plot.snags.each do |snag| %>
      <%= snag.title %>
    <% end %>
  <% end %>
<% end %>
iGian
  • 11,023
  • 3
  • 21
  • 36
0

You can find all the plot_snags in a single query. And iterate the @plot_snags variable in the view.

private

def get_snags(plots)
  plot_ids = plots.pluck(:id)   
  @plot_snags = Snag.where(plot_id: plot_ids)
end
Dyaniyal Wilson
  • 1,012
  • 10
  • 14
  • This performs two queries since you are using pluck which is not needed. Just pass the scope `Snag.where(plot_id: plots)`. – max Apr 29 '19 at 16:23