Carrierwave and has_many - ruby-on-rails

I have Product model like this:
class Product < ActiveRecord::Base
has_many :images, :class_name => 'ProductImage', :order => 'position DESC', :dependent => :destroy
def image_thumb
images.first.image.thumb.url
end
def image
images.first.image.url
end
end
ProductImage model:
class ProductImage < ActiveRecord::Base
attr_accessible :image, :position, :product_id, :title
belongs_to :product
default_scope order('position ASC')
mount_uploader :image, ProductImageUploader
end
Uploader model:
class ProductImageUploader < CarrierWave::Uploader::Base
...
def default_url
asset_path([version_name, "default.jpg"].compact.join('_'))
end
end
But if I don't upload any image for product, I will get 'nil' in image_thumb and image methods. How get default_url if no one image uploaded and relation between Product and ProductImage models are one-to-many?

If you don't have access to an uploader, an uploader can't help you, so you have to do it by hand. You're already using a presenter (more or less), so this is extremely easy:
def image_thumb
if images.any?
images.first.image.thumb.url
else
asset_path("default.jpg")
end
end
def image
if images.any?
images.first.image.url
else
asset_path("thumb_default.jpg")
end
end
Similar code works for belongs_to relationships.

What is the value you are getting for default_url?
Maybe the path is not evaluating correctly.
Try something like this (of course correct the path below to what it should be):
class ProductImageUploader < CarrierWave::Uploader::Base
...
def default_url
"/assets/" + [version_name, "default.jpg"].compact.join('_')
end
end

Related

Rails : Error multiple file upload, empty array

i have big problem, my rails application cannot upload photos correctly i get this error every time.
you can se on right of photos cannot upload cloudinary url
I have to do this since the admin and not from the site itself to add pictures
cars_controller.rb
def index
#cars = Car.all()
end
def show
#car = Car.friendly.find(params[:id])
#photos = #car.photos
end
end
photos_uploader.rb
include Cloudinary::CarrierWave
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_whitelist
%w(jpg jpeg gif png)
end
photo.rb
mount_uploaders :photos, PhotosUploader
belongs_to :car
car.rb
extend FriendlyId
friendly_id :title, use: :slugged
mount_uploader :photo, PhotoUploader
has_many :photos
You can see my error
mount_uploaders are not currently supported in the Cloudinary Ruby gem. The issue can be tracked here https://github.com/cloudinary/cloudinary_gem/issues/304.
There is a sample project (https://github.com/taragano/Cloudinary_multiple_uploads) that illustrates a temporary workaround. The models are album and photo, where album has a has_many relationship to photos and photo has a belongs_to relationship to album.
The models (https://github.com/taragano/Cloudinary_multiple_uploads/tree/master/app/models) should look like this:
class Photo < ActiveRecord::Base
belongs_to :album
mount_uploader :image, ImageUploader
end
class Album < ActiveRecord::Base
has_many :photos, dependent: :destroy
end
While in the controller (https://github.com/taragano/Cloudinary_multiple_uploads/blob/master/app/controllers/albums_controller.rb), you'll need to iterate over each photo and store it to the album that it belongs to:
def store_photos
photos = params[:album][:photos]
photos.each{|photo| #album.photos.create(image: photo)} if photos
end

Using custom methods in scope/refactoring custom methods

I am making a Instagram-like clone where users upload pics that get voted on.
How can I refactor this code?
How can I default scope it by decreasing percent?
class Picture < ActiveRecord::Base
mount_uploader :picture, PictureUploader
has_and_belongs_to_many :tags
has_many :votes, :dependent => :destroy
def vote_count
return self.votes.count
end
def up_votes
return self.votes.where('up like ?', true).count.to_f
end
def down_votes
return self.votes.where('up like ?', false).count.to_f
end
def percent
return self.up_votes/self.vote_count
end
end
FYI my Vote model just tracks the picture and user id and has up:boolean, :default => false
This all seems less concise than it could be, how would you write this better?
class Picture < ActiveRecord::Base
mount_uploader :picture, PictureUploader
has_and_belongs_to_many :tags
has_many :votes, :dependent => :destroy
def vote_count
return self.votes.count
end
def votes_status(status)
return self.votes.where('up like ?', status).count.to_f
end
def percent
return self.votes_status(true)/self.vote_count
end
end

How to best way define the main object in the polymorphic relations?

I have models:
dress.rb
class Dress < ActiveRecord::Base
has_many :images, as: :imageable
end
publication.rb
class Publication < ActiveRecord::Base
has_many :images, as: :imageable
end
image.rb
class Image < ActiveRecord::Base
mount_uploader :name, ImageUploader
belongs_to :imageable, polymorphic: true
end
I have two ideas how its write:
Add main_image_id (:integer) to Image, Publication and other models. Also can create a relation has_one :main_image, class_name: 'Image', foreign_key: :main_image_id. But this is bad way because this field need add to every created Model which has polymorphic relations with Image.
Add main (:boolean) to Image. And check every time true or false. This is bad way too because table images will have unused fields.
Who has any thoughts?
2nd way is better. this way you can order images by this field and make scopes.
# image.rb
scope main, ->{where(main: true)}
# publication.rb
scope images, ->{images.order(:main)}
#images.main #=> will give you needed result as
#publiscations.images #=> will give you first image as main.
And if you think about extra column, you will need to add it anyway. So why not to use it where it is more useful
STI
Maybe try STI
#app/models/asset.rb
Class Asset < ActiveRecord::Base
mount_uploader :name, ImageUploader
end
#app/models/image.rb
Class Image < Asset
belongs_to :imageable, polymorphic: true
delegate :url, to: :asset #-> not used Carrierwave, so I don't know how this is done
end
#app/models/dress.rb
Class Dress < ActiveRecord::Base
has_many :images, as :imageable
end
#app/models/publication.rb
Class Publication < ActiveRecord::Base
has_many :images, as :imageable
end
This will give you the ability to call the following:
#app/controllers/dresses_controller.rb
Class DressesController < ApplicationController
def index
#dresses = Dress.all
end
end
#app/views/dresses/index.html.erb
<% #dresses.each do |dress| %>
<%= dress.images.each do |image| %>
<%= image_tag image.url %>
<% end %>
<% end %>

Rails Carrierwave stor_dir location not valid (Model.#{association} returns nil)

I am using carrierwave to upload images to my webapp.
It has become necessary to upload them to the location of the parent model.
Ie.
The parent is house which has many images.
So I want to store the images in
public/uploads/houses/images/[:house_id]/
This is my current setup.
..uploaders/image_uploader.rb
def store_dir
puts "uploads/house/#{model.house_id}/#{mounted_as}/#{model.id}"
"uploads/house/#{model.house_id}/#{mounted_as}/#{model.id}"
end
The puts statement prints out the correct path that I would like but the path saved does not match.
It appears that the model.house_id is returning nil
House Model
class House < ActiveRecord::Base
attr_accessible :address, :description, :title, :price, :image, :image_id, :images, :image_cache
has_many :images
mount_uploader :image, ImageUploader
end
Image Model
class Image < ActiveRecord::Base
attr_accessible :house_id, :image
mount_uploader :image, ImageUploader
belongs_to :house
end
How do I get the correct path/ What am I doing wrong :(
Please try:
def cache_dir
"#{Rails.root}/public/uploads/houses/images"
end
def store_dir
"#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

STI & Polymorphic association & user_id

So I have an assets model which is inherited by images and files as STI. Products has many images as assetable. This polymorphic association is working fine but I can't figure out how to add the user_id to every asset. A asset always belongs to a user no matter if its an image or file. Please look at my code below. I'm pretty sure there's something I need to do within the controllers create method but I'm not sure what? I've tried merging :user_id but this just returns nil when looking at the console log. Ideally what I'd also like to do is #user.images which will display all the images that the user has uploaded or even #user.files
class User < ActiveRecord::Base
has_many :products
has_many :assets
end
class Asset < ActiveRecord::Base
belongs_to :assetable, :polymorphic => true
belongs_to :user
end
class Image < Asset
mount_uploader :filename, ImageUploader
attr_accessible :filename, :assets
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :images, as: :assetable
accepts_nested_attributes_for :images
attr_accessible :name, :price, :images_attributes
validates_presence_of :name
end
class ProductsController < ApplicationController
def create
#product = Product.new(params[:product])
#product.user_id = current_user.id
params[:product][:images_attributes].each do |key, image|
# image.user_id = current_user.id
image.merge(:user_id => 1)
end
#product.save
end
end
def create
params[:product][:images_attributes].each do |key, image|
image.merge!(:user_id => current_user.id)
end
#product = Product.new(params[:product])
#product.user_id = current_user.id
#product.save
end
By the way, you'd better to replace inheritance logic into the model:
class Image < Asset
mount_uploader :filename, ImageUploader
attr_accessible :filename, :assets
before_save do
self.user = assetable.try(:user)
end
end
# controller
def create
#product = Product.new(params[:product])
#product.user = current_user
#product.save
end

Resources