Search code examples
ruby-on-railsruby-on-rails-4activerecordrails-activerecordnested-attributes

Display nested attributes together in view or index.html.erb


I have a Product model with most of the attributes and a has_many relationship through to my Product_Images model. All of the updates, edits etc work like a charm but I'm having difficulty bringing data through to a front end bootstrap theme.

What I'm trying to do is have the last 5 products and there default images come through to so I can have a Product Image and associated product Attributes together. At present I have all the attributes and all of the images in 2 separate arrays.

I have looked at group_by but I cant work out how to have the attributes + images grouped together from two arrays by product_id. I just have no idea how to go about this.

app/controller/home_controller.html.erb

class HomeController < ApplicationController
  def index
    @products = Product.last(5)
    @product_ids = @products.map(&:id)
    @product_images = ProductImage.where(:product_id => @product_ids, 
    :default_image => true )
  end
end

The below basically dumps the two arrays but they are not together.Image / Attributes per product_id

app/views/home/index.html.erb

 <% @products.each do |pd| %>
      <%= pd.product_name %>
  <% end %>
  <% @product_images.each do |pi| %>
      <%= image_tag (pi.product_image(:medium)) %>
  <% end %>

What I'm looking for is an output something like this

<div class="col-md-3 col-sm-6 hero-feature">
      <div class="thumbnail">
        <#PRODUCT_IMAGE product_id1> 
        <div class="caption">
          <h3>#PRODUCT_NAME product_id1</h3> 
          <p>#PRODUCT_DESCRIPTION product_id1</p> 
          <p>
          </p>
        </div>
      </div>
    </div>
 <div class="col-md-3 col-sm-6 hero-feature">
          <div class="thumbnail">
            <#PRODUCT_IMAGE product_id2> 
            <div class="caption">
              <h3>#PRODUCT_NAME product_id2</h3> 
              <p>#PRODUCT_DESCRIPTION product_id2</p> 
              <p>
              </p>
            </div>
          </div>
        </div>
 ...etc

Answer SQL Output; Cheers suslov

 Product Load (0.0ms)  SELECT  `products`.* FROM `products`   ORDER BY `products`.`id` DESC LIMIT 5
  SQL (1.0ms)  SELECT  DISTINCT `products`.`id` FROM `products` LEFT OUTER JOIN `product_images` ON `product_images`.`product_id` = `products`.`id` WHERE `product_images`.`product_id` IN (1, 2) AND `product_images`.`default_image` = 1  ORDER BY `products`.`id` DESC LIMIT 5
  SQL (0.0ms)  SELECT `products`.`id` AS t0_r0, `products`.`product_name` AS t0_r1, `products`.`product_description` AS t0_r2, `products`.`product_type_id` AS t0_r3, `products`.`product_category_id` AS t0_r4, `products`.`product_colour_id` AS t0_r5, `products`.`product_size_id` AS t0_r6, `products`.`created_at` AS t0_r7, `products`.`updated_at` AS t0_r8, `product_images`.`product_id` AS t1_r0, `product_images`.`created_at` AS t1_r1, `product_images`.`updated_at` AS t1_r2, `product_images`.`id` AS t1_r3, `product_images`.`product_image_file_name` AS t1_r4, `product_images`.`product_image_content_type` AS t1_r5, `product_images`.`product_image_file_size` AS t1_r6, `product_images`.`product_image_updated_at` AS t1_r7, `product_images`.`default_image` AS t1_r8 FROM `products` LEFT OUTER JOIN `product_images` ON `product_images`.`product_id` = `products`.`id` WHERE `product_images`.`product_id` IN (1, 2) AND `product_images`.`default_image` = 1 AND `products`.`id` IN (2, 1)  ORDER BY `products`.`id` DESC
  Rendered home/index.html.erb within layouts/application (0.0ms)

Updated index.htmml.erb partial from the answer by suslov

 <div class="row text-center">
      <% @product_images.each do |pd| %>
          <%= content_tag :div, :class => "col-md-3 col-sm-6 hero-feature" do %>
          <% pd.product_images.each do |i| %>
              <div class="thumbnail">
                <%= image_tag (i.product_image(:medium)) %>
          <% end %> </div>
          <div class="caption">
            <h3><%= pd.product_name %></h3>
            <p><%= pd.id %></p>
            <p></p>
          </div>
          <% end %>
      <% end %>
    </div>

Solution

  • You can try with includes if you have explicitly set has_many association in your Product model (assuming is is named product_images):

    app/controller/home_controller.rb:

    @products = Product.includes(:product_images)
                       .where(product_images: { default_image: true )
                       .last(5)
    

    app/views/home/index.html.erb:

    <div class="col-md-3 col-sm-6 hero-feature">
      <div class="thumbnail">
        <% @products.each do |pd| %>
            <% pd.product_images.each do |i| %>
                <%= image_tag (i.product_image(:medium)) %>
            <% end %>
        <div class="caption">
          <h3><%= pd.product_name %></h3> 
          <p><%= pd.id %></p> 
          <p></p>
        </div>
        <% end %>
      </div>
    </div>