I'm modifying a Rails app I've been working on.
I installed a model images.rb
to handle all images for products.
When the user has selected a product the user sees the product at app/views/products/show.html.erb
And at the bottom of the show.html.erb
the app gives the user suggestions for similar product in the same category as the product the user is looking at.
Before I added the image.rb
model to handle the images each product had one picture attached to it and every thing worked, but now I'm getting an error. Below is the code I used to display the random products in the same category:
the show.html.erb
<div class="row product-teaser">
<h4 class="text-center teaser-text"> similar products to <%= @product.title %> : </h4>
<% @products_rand.each do |product| %>
<div class="col-sm-2 col-xs-3 center-block product-thumbs-product-view" >
<%= link_to product_path (product) do %>
<%= image_tag @product.image.url, :size => "100%x100%", class: "img-responsive center-block" %>
<% end %>
<h5 class="text-center"><%= link_to product.title, product, class: "text-center" %></h5>
</div>
<% end %>
</div>
And in the products_controller.rb
show
method I had this variable to fetch the random products from the same category.
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
def show
@products_rand = Product.where(category_id: @product.category_id).order("RANDOM()").limit(6)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
@product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :price_usd, :image, :category_id, :stock_quantity, :label_id, :query, :slug, images_attributes: [:image , :id , :_destroy])
end
end
After I added the image.rb
I always get this error: undefined method 'url' for "":String
when trying to load the show page. The error is appearing in this line: <%= image_tag @product.image.url, :size => "100%x100%", class: "img-responsive center-block" %>
the product.rb
model
class Product < ActiveRecord::Base
acts_as_list :scope => [:category, :label]
belongs_to :category
belongs_to :label
has_many :images
accepts_nested_attributes_for :images
has_many :product_items, :dependent => :destroy
validates :title, :description, presence: true
validates :price_usd, :price_isl, numericality: {greater_than_or_equal_to: 0.01}
validates :title, uniqueness: true
end
the image.rb
model
class Image < ActiveRecord::Base
belongs_to :product
has_attached_file :image, styles: { medium: "500x500#", thumb: "100x100#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
I'm not sure what to do, can someone advise me?
If your Product has_many :images
then @product.image.url
is not going to work.
@product.images.sample
will give you a random image for that product.
It looks like you're using Paperclip
, which you have configured to add an image
attachment to your Image
model, so you need to add an extra method to your chain:
@product.images.sample.image.url
will retrieve the URL for the image attachment of a randomly selected image
association.
@product.image
is currently returning an empty string, so you must have an image
column on your products
table of type string
or text
, or an image
method on your model. If you don't need it anymore then you should remove it.
If it's a column in your table, in a migration file:
def change
remove_column :products, :image
end
As suggested by MrYoshiji, getting a random image would be more efficiently achieved at the database level, especially if a product has a lot of associated images. A scope method on the Image
model would do the trick, along with a Product
method to abstract it and simplify your view.
class Image < ActiveRecord::Base
scope :random, -> { order("RANDOM()").limit(1) }
end
class Product < ActiveRecord::Base
def random_image
images.random.take
end
end
Then in your view
@product.random_image.image.url