20 October 2015

This is an industrial site where a pipe rack runs through several kilometres. This rack, as usual, has several bents, in this case, they call loops (even though they are not loops!) All the site is divided into areas. Each area can have several loops. Each loop can have several pipes. Not necessarily all the pipes that belong to an area pass through a loop.

My models are (simplified):

# models/loop.rb
class Loop < ActiveRecord::Base
  belongs_to :area
  has_many :pipes
end

# models/area.rb
class Area < ActiveRecord::Base
  has_and_belongs_to_many :pipes
  has_many :loops
  has_many :looppipes, through: :loops, source: :pipes
end

# models/pipe.rb
class Pipe < ActiveRecord::Base
  belongs_to :loop
  has_and_belongs_to_many :areas
end

The line has_and_belongs_to_many :pipes gives the association for those pipes that have no loop associated.

To get the pipes that don’t pass through any loop of certain area, that is, pipes directly assigned, we can write

area.pipes

The line has_many :looppipes, through: :loops, source: :pipes in the area model gives the association area-pipe for those pipes that pass through a loop.

To get the pipes that go through any loop of certain area, we can write

area.looppipes

To join both lists we can write

area.pipes + area.looppipes

When the loop information is needed:

area.looppipes.includes(:loop)
area.looppipes.includes(:loop).first.loop.name

area.pipes.includes(:loop)

In the views

area/show.html.erb

<%= render partial: 'area_pipes', locals: { area: @area, pipes: @area.pipe, with_loop: false, listing_title: t(:Listing_pipes_without_loop) } unless @area.pipes.empty? %>

<%= render partial: 'area_pipes', locals: { area: @area, pipes: @area.looppipes.includes(:loop), with_loop: true, listing_title: t(:Listing_pipes_through_loop)  } unless @area.looppipes.empty? %>

area/_area_pipes.html.erb

<h3><%= listing_title %></h3>

<table class="table table-striped">
  <thead>
    <tr>
      <th><%= t :Name %></th>
    <% if with_loop %>  <th><%= t :Loop %></th> <% end -%>
      <th class="centered"><%= t :Areas %></th>
      <th colspan="1"></th>
    </tr>
  </thead>

  <tbody>
    <% pipes.each do |pipe| %>
      <tr>
        <td><%= pipe.name %></td>
       <% if with_loop %> <td><%= pipe.loop.name %></td> <% end -%>
        <td class="centered"><%= pipe.areas.count %></td>
        <td><%= link_to t(:show_pipe_info), pipe if policy(Pipe).show? %></td>
        <td><%= link_to t(:Remove_pipe), area_remove_pipe_path(area, pipe), method: :delete, data: { confirm: t(:Are_you_sure) } if policy(Area).remove_pipe? %></td>
      </tr>
    <% end %>
  </tbody>
</table>