Daði Hall Daði Hall - 5 months ago 8
Ruby Question

undefined method `image' for #<Array> when using group_by

Hi can anyone point me to the right direction? I´m trying to show images on

views/pages/index.html.erb
the images are uploaded on
views/products/new.html.erb
through the
_form.html.erb
partial. Each product/picture then belongs to a category which I can select in the
_navbar.html.erb
and is then directed to the
views/categories/show.html.erb
to see pictures of each product in that category and so on.

That is all working fine

But now I want to display the last added picture in each category on the
views/pages/index.html.erb
and I´m always getting this error :
undefined method 'image' for #<Array:0x007f8d1fb19ff0>


I´m pretty lost at the moment, and hopefully someone can guide me to the right path.

My code id like this:

pages_controller.rb

class PagesController < ApplicationController
def index
@products = Product.all.order(created_at: :desc).group_by(&:category_id)
end

def about
end

def location
end

def stockists
end
end


views/pages/index.html.erb

<% @products.each do |product| %>
<div class="col-lg-3 col-sm-6 col-xs-12 center-block " >
<%= image_tag product.image.url(:medium) %>
<p><%= product.name %></p>
<p><%= product.category.name %></p>
<% end %>
</div>


And then I have, the products.rb and category.rb

product.rb

class Product < ActiveRecord::Base
mount_uploader :image, ImageUploader

validates_presence_of :name, :price
validates_numericality_of :price

belongs_to :category
end


category.rb

class Category < ActiveRecord::Base
has_many :products

end


this as part of the schema.rb

create_table "products", force: :cascade do |t|
t.string "name"
t.string "description"
t.float "price"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id", default: 1
end

add_index "products", ["category_id"], name: "index_products_on_category_id", using: :btree


and in the end there is this part

add_foreign_key "order_items", "orders", on_delete: :cascade
add_foreign_key "order_items", "products"
add_foreign_key "orders", "users", on_delete: :cascade
add_foreign_key "products", "categories"
end

Answer

You are using group_by in the controller, an enumerable method that returns a hash of Product arrays keyed by category_id.

@product = {
  :category1 => [#<Product category_id=1>, #<Product category_id=1>, ...],
  :category2 => [#<Product category_id=2>, #<Product category_id=2>, ...]
}

When you loop through @products in the view, you are looping through a hash where each iteration is passing an array.

The product variable does not contain a product, but an array of products.

<% @products.each do |product| %>             # product is type Array!
  <%= image_tag product.image.url(:medium) %> # Array.image throws an error! 
<% end %>  

You must create an outer loop to step through the hash.

<% @products.each do |category, products| %>
  <% products.each do |product| %>
    # do stuff       
  <% end %>
<% end %>
Comments