Search code examples
ruby-on-railsrubyransack

Ransack: Show the attribute of a has_many relationship sorted by Ransack


I have a Commodity(name:string) model and a Price(amount:float) model such that:

class Commodity < ApplicationRecord
  has_many :prices
end

And

class Price < ApplicationRecord
  belongs_to :commodity
end

Thus, one commodity can have many prices.

I have a Ransack search form for Commodity, which obviously enables a user to search for commodities. I wish to include a sort_link(@q, :prices_amount) sorting filter. Clicking this link should display all the commodities sorted according to their prices (if one commodity has multiple prices, that commodity will show multiple times, with each repeated commodity's price shown accordingly). Currently, Ransack does indeed show a commodity multiple times, (as many as the number of prices each commodity has) but I do not know a way to display that price for each repeated commodity.

I wish to know how should I display that price in my frontend. I display the query results via:

<%=@commodities.each do |commodity|%>
  <%=commodity.name%>    
  <%=commodity.prices.first.amount%> <!-- In place of prices.first, I was to display the amount that Ransack found -->
<%end%>

I'm using prices.first.amount right now as a placeholder. How do I replace this by the amount that Ransack found while sorting?


Solution

  • I would recommend creating a scope to include the price with the Commodity instance. e.g.

    class Commodity < ApplicationRecord
      scope :with_price, -> {joins(:prices).select("commodities.*, prices.amount as price_amount")}
    end
    

    This will create a virtual attribute price_amount on your instances of Commodity

    In the controller it would be something like

    @q = Commodity.ransack(params[:q])
    @commodities = @q.result.with_price
    

    Assuming that you're "Displaying" these as a table you can display the results as requested using the following

    <table>
      <thead>
        <tr>
          <th><%= sort_link(@q, :name, 'Commodity' %></th>
          <th><%= sort_link(@q, :prices_amount, 'Price') %></th>
        </tr> 
      </thead>
      <tbody>
        <% @commodities.each do |commodity| %>
          <tr> 
            <td><%= commodity.name %></td>
            <td><%= number_to_currency(commodity.price_amount) %></td>
          </tr>
        <% end %>
      </tbody>
    </table>