spencer
spencer

Reputation: 41

Trying not to repeat myself with Rails data manipulation

I'm fairly new to rails, an an intermediate programmer in general, but I'll try to be as clear as I can.

I have a database table for Products, which owns a field called category. Category has two possible values, call them Category1 and Category 2. The goal is to retrieve all the Products and display them in HTML organized by Category. I can make this work, but I know there has to be a better way.

My method now is to get my Products like so:

@category1_products = Product.all(conditions: { category: "Category1" })
@category2_products = Product.all(conditions: { category: "Category2" })

and then output the data something like this:

<table>
<tr>
  <td>Category1 Name</td>
<% @category1_products.each do |product| %>
  <td><%= product.name %></td>
  <td><%= product.description %></td>
  <td><%= product.price %></td>
<% end %>
</tr>
<tr>
  <td>Category2 Name</td>
<% @category2_products.each do |product| %>
  <td><%= product.name %></td>
  <td><%= product.description %></td>
  <td><%= product.price %></td>
<% end %>
</tr>
</table>

I would like to accomplish this using a single instance: get all Products at once, group them by Category, and then output them by looping through one Category at a time (including the Category Names). This seems like a pretty elementary concept to me, but I'm having trouble getting my head around it.

Upvotes: 3

Views: 104

Answers (2)

Chris Salzberg
Chris Salzberg

Reputation: 27374

Rails' group_by is great for this type of problem:

@grouped_products = Product.all.group_by(&:category)

and then in the view, just loop over @grouped_products:

<table>
  <tr>
  <% @grouped_products.each do |category, products| %>
    <td><%= category %></td>
    <% products.each do |product| %>
      <td><%= product.name %></td>
      <td><%= product.description %></td>
      <td><%= product.price %></td>
    <% end %>
  <% end %>
  </tr>
</table>

Upvotes: 1

Zach Kemp
Zach Kemp

Reputation: 11904

@products_by_category = Product.all.group_by(&:category)

This is a Ruby (read: not ActiveRecord) method to turn an Array into a Hash based on some condition of the objects it contains.

In your view (assuming you want one row per product, and not one per category):

<table>
  <% @products_by_category.each do |category,products| %>
    <tr>
      <th><%= category %></th>
    </tr>
    <% products.each do |product| %>
      <tr>
        <td><%= product.name %></td>
        <td><%= product.description %></td>
        <td><%= product.price %></td>
      </tr>
    <% end %>
  <% end %>
</table>

Upvotes: 1

Related Questions