I have a Photo Model that Is going to be a polymorphic model. If I submit my parent model and save it. If it doesn't have any photos, when I do to display the default_url of a photo it won't show anything because there is no photo. When a photo is attached to a model, meaning there is only one, it will return a default_url when the field is null but when there is no results, it doesn't return a default_url. I don't want to enter null records just to fix the default_url issue.
I have found that if i do the following it will return the default_url but not sure this is the best
ImageUploader.new.default_url(:small) if #photos.blank?
This works but it is sloppy..i think. Anyone have a better idea? Maybe a find method on the photos model or something better that will return an object that will have Valid urls whether there is something there or not.
class Photo < ActiveRecord::Base
# Concerns
include Guidable
default_scope :order => 'photos.order DESC'
belongs_to :attachable, :polymorphic => true
mount_uploader :image, ImageUploader
def attachable?
!!self.attachable
end
end
I'm going to answer my own question but still not convinced this is the best option
module PhotosHelper
def photo_url(photo, size)
defined?(photo.image) ? photo.image.url(size) : ImageUploader.new.send(size).default_url
end
end
Would prefer to have the model just return something if there are no images.
Related
I've this models:
Prodcuts -> Products_Images.
I can add multiple images from a form uploading the image that it's my computer. I want to add images from URLs instead of locally images.
Paperclip has added this feature:
https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
but I don't know how to apply it in a has_many association.
I've tried adding a method in ProductImages model and call it for each URL after product is created. I don't know if I must use this method directly in Product model.
Where should I try to put the method of the wiki of Paperclip?
Here is a great gist (that I did not write). It should get you there: https://gist.github.com/jgv/1502777
require 'open-uri'
class Photo < ActiveRecord::Base
has_attached_file :image # etc...
before_validation :download_remote_image, :if => :image_url_provided?
validates_presence_of :image_remote_url, :if => :image_url_provided?, :message => 'is invalid or inaccessible'
private
def image_url_provided?
!self.image_url.blank?
end
def download_remote_image
io = open(URI.parse(image_url))
self.original_filename = io.base_uri.path.split('/').last
self.image = io
self.image_remote_url = image_url
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
All credit to the author.
In the future, it's usually best to post the code with your attempt to solve the problem.
I have white listed some of the extensions in the carrierwave uploader class
def extension_white_list
%w(doc docx)
end
In some cases I would like to skip the Integrity validation while saving a record. But as per their documentation validates_integrity_of validation exist by default.
https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Validate-uploads-with-Active-Record
can anyone please tell me how to skip such validation ?
in uploaders/file_uploader.rb
def extension_white_list
if model.do_i_need_validation?
%w(doc docx)
else
file.extension
end
end
and define this instance method in the model
def do_i_need_validation?
condition? ? true : false
end
Just replace the content of the method suitable to your app
I couldn't find anything about this in any of carrierwave's documentation, but reading its source code, one can pass specific uploader options in the mount_uploader call:
mount_uploader :field, MyUploader, options
Validations configuration do exist in uploader options, so you can, for example, disable all validations using:
mount_uploader :field, MyUploader, validate_download: false, validate_integrity: false, validate_processing: false
Note that when doing this the errors are silently ignored, so saves will succeed. This could be unexpected behavior. You can check if the operation actually had any errors using the model helpers <field>_processing_error, <field>_integrity_error and <field>_download_error:
class Article < ActiveRecord::Base
mount_uploader :image, ImageUploader, validate_integrity: false
end
article = Article.find(1)
article.update_attributes!(title: "New article title", image: open("/path/to/invalid_image.jpg")) # => this will actually succeed
article.image_integrity_error # => returns the error message from carrierwave
I have a project using Paperclip gem for attachments and Globalize3 for attribute translation. Records need to have a different attachment for each locale.
I though about moving Paperclip attributes to translation table, and that might work, but I don't think that would work when Paperclip needs to delete attachments.
What's the best way to achieve something like that?
UPDATE: to be clear, I want this because my client wants to upload different images for each locale.
Unfortunately I didn't find a way to do this using Globalize3. In theory, I could have added a separate model for image and add image_id to list of translated columns (to have something like MainModel -> Translation -> Image), but it seems that Globalize has some migration issues with non-string columns.
Instead of using Globalize3, I did this with a separate Image model with locale attribute and main model which accepts nested attributes for it. Something along the lines of:
class MainModel < ActiveRecord::Base
has_many :main_model_images
accepts_nested_attributes_for :main_model_images
# return image for locale or any other as a fallback
def localized_image(locale)
promo_box_images.where(:locale => locale).first || promo_box_images.first
end
end
class MainModelImage < ActiveRecord::Base
belongs_to :main_model
has_attached_file :image
validates :locale,
:presence => true,
:uniqueness => { :scope => :main_model_id }
end
Tricky part was getting form to accept nested attributes only for one image, instead of all images in has_many relation.
=f.fields_for :main_model_images, #main_model.image_for_locale(I18n.locale) do |f_image|
=f_image.hidden_field :locale
=f_image.label :image
You could also try the paperclip-globalize3 gem, it should handle the case you describe. https://github.com/emjot/paperclip-globalize3
Ok since you asked me to share my solution to this problem even though I am using Carrierwave as a library for uploading here is it:
Ok so I would have a model setup like this:
class MyModel < ActiveRecord::Base
# ...
translates :attr_one, :attr_two, :uploaded_file
Now what I need for CarrierWave to work is place to attach the uploader to and that can be done on the Translation model
Translation.mount_uploader :uploaded_file, FileUploader
end
Now for your question about deleting, I think though I haven't needed to do it but it should work as the README says it should but on the translation model. https://github.com/jnicklas/carrierwave#removing-uploaded-files
MyModel.first.translation.remove_uploaded_file!
I haven't taken a look at paperclip for a good 2 years and if this is not applicable knowledge I suggest you try out carrierwave.
first of all, i am using rails 3.1.3 and carrierwave from the master
branch of the github repo.
i use a after_init hook to determine fields based on an attribute of
the page model instance and define attribute accessors for these field
which store the values in a serialized hash (hope it's clear what i am
talking about). here is a stripped down version of what i am doing:
class Page < ActiveRecord::Base
serialize :fields, Hash
after_initialize :set_accessors
def set_accessors
case self.template
when 'standard'
class << self
define_method 'image' do
self.fields['image']
end
define_method 'image=' do |value|
self.fields['image'] = value
end
end
mount_uploader :image, PageImageUploader
end
end
end
end
leaving out the mount_uploader command gives me access to the
attribute as i want. but when i mount the uploader a get an error
message saying 'undefined method new for nil class'
i read in the source that there are the methods read_uploader and
write_uploader in the extensions module.
how do i have to override these to make the mount_uploader command
work with my 'virtual' attribute.
i hope somebody has an idea how i can solve this problem. thanks a lot
for your help.
best regard. dominik.
Same problem but solved in your model you should override read_uploader(column) and write_uploader(column, identifier) instance methods. I also have a problem with #{column}_will_change! and #{column}_changed? for a virtual column so I had to define them too:
class A < ActiveRecord::Base
serialize :meta, Hash
mount_uploader :image, ImageUploader
def image_will_change!
meta_will_change!
#image_changed = true
end
def image_changed?
#image_changed
end
def write_uploader(column, identifier)
self.meta[column.to_s] = identifier
end
def read_uploader(column)
self.meta[column.to_s]
end
end
Now there's also an add-on to carrierwave which provides the exact functionality as described by Antiarchitect:
https://github.com/timsly/carrierwave-serializable
Listing < AR
has_many :images
accepts_nested_attributes_for :images, :allow_destroy => true
validate :validate_image_count
def validate_image_count
errors.add_to_base("too few") if images.length < 1
end
end
Image < AR
belongs_to :listing
end
In my Listing#edit form I use fields_for to provide fields for all the images along with checkboxes to delete images. This is working fine. I want to enforce a check such that a listing is valid only if it had at least one image and at most 6.
In my current setup I can go to edit and delete all the images, and then update the listing.
I have tried using a validation as shown above but thats not being called. Could be just the way nested_attributes work in rails. Whats the best way to enforce this check?
as the images won't be deleted when you call the validation method it would return true on the image length. You can use marked_for_destruction?
def validate_image_count
errors.add_to_base("too few") self.images.any? { |i| i.marked_for_destruction? }
end