validates_attachment for optional field - ruby-on-rails

I have an uload field which is optional, it can be left empty. But when it is is used, I want to validate the size and content of the attachment. So I use this validation in the model:
validates_attachment :attachment, content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }, size: { in: 0..500.kilobytes }
This works when there is an attachment, but fails when it is left empty. How can I make sure it only validates when there is an attached file?
The solutions mentioned here are not working unfortunately.

The link you provided is giving you what I would suggest - using the if: argument
--
if:
Using if: in your validation basically allows you to determine conditions on which the validator will fire. I see from the link, the guys are using if: :avatar_changed?
The problem you've likely encountered is you can either use a Proc or instance method to determine the condition; and as these guys are using a method on avatar (albeit an inbuilt one), it's not likely going to yield the result you want.
I would do this:
validates_attachment :attachment, content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }, size: { in: 0..500.kilobytes }, if: Proc.new {|a| a.attachment.present? }
This basically determines if the attachment object is present, providing either true or false to the validation

try this:
has_attached_file :attachment, :styles => { :small => "200x200>" }
validates_attachment :attachment,
:size => { :in => 0..500.kiobytes },
:content_type => { :content_type => /^image\/(jpeg|png|gif|tiff)$/ }
its working on my app. except i have set a default attachment in case user chooses not to upload one.

Related

update_attributes validation fails though values are correct

I have in my model
class Account < ActiveRecord::Base
validates_length_of :amount, :in 1..255, :on => update, :if => Proc.new { |a| false if a.id == nil;a.amount.blank? }
validates_length_of :name, :in 1..255, :on => update, :if => Proc.new { |a| false if a.id == nil;a.name.blank? }, :unless => user_has_amount?
end
when I comment out the if condition, it works fine but with them validation fails which is confusing. I know that the validation should only run if the proc returns true or unless returns false
in my controller I have
#account.update_attributes({:name => "king", :amount => "1223"}
the save fails and when I check errors I get
#account.errors.details
{:name =>[{:error=>:too_short, :count=>1}], :amount =>[{:error=>:too_short, :count=>1}]}
Strong Params are not an issue because I have
def self.params
params.require(:account).permit!
end
I have no idea why it fails though the value are present and correct.
Try this the following:
class Account < ActiveRecord::Base
validates :amount, length: { in: 1..255 }, on: :update
validates :name, length: { in: 1..255 }, on: :update
end
Check your strong parameters. Your error tells you that something is wrong before you get to validation: :name =>[{:error=>:too_short, :count=>1}] This is saying that the minimum string count is 1 but that your string is not even that long. Here is the docs on that.
You can try: Account.find(1).update_attributes({:name => "king", :amount => "1223"} to see if #account is not being set properly.
You can also customize the language on your errors to help further:
validates_length_of : name, within: 1..255, too_long: 'pick a shorter name', too_short: 'pick a longer name'
The issue that was happening was for one reason. The code was inheriting from a class that had:
slef.reload
in one of the function that were being called during validations.
so every time we try to update the update failed because once that validation was hit it reloaded the original values from database and ignored new values which if old values are empty is just a head scratcher.
Thanks everyone for the help

Disable auto rotate in paperclip

I'm using Paperclip in my project but some of my users are complaining that it's incorrectly rotating some images.
For some reasons I can't even imagine I figured it out that some files are with wrong exif orientation attributes. I was looking and I saw that paperclip calls ImageMagick by default using -auto-orient. I saw that the Thumbnail processor has an option to turn auto-orient on or off.
But I couldn't find a way to pass this to the Processor.
This is the code I have:
has_attached_file :photo,
styles: { :square => "400x400#" }
Does anyone now how to do that?
Thanks!
In the end I created a new processor which extends from the paperclip default Thumbnail processor to send the correct options.
class WithouAutoOrientProcessor < Paperclip::Thumbnail
def initialize(file, options = {}, attachment = nil)
options[:auto_orient] = false
super
end
end
And in the model I added
has_attached_file :photo,
styles: { :square => "400x400#" },
processors: [:WithouAutoOrientProcessor]
Although it is a valid option to add your own processor, this is how you pass the option to the processor:
In your styles hash replace your dimension strings with another hash
Put your old dimensions in the key geometry into this hash
The other key/value pairs are the options passed to the processor
You can of course pass auto_orient: false, too
Applying this to your model's code:
has_attached_file :photo,
styles: { square: { geometry: "400x400#", auto_orient: false } }

Ruby validation - multiple permutations for a single hash

Say there is a hash field that can have two possible value permutations, "foo" and "bar". How can I validate the hash value is one of the two?
class ValidateMe
validates :type => { :type => "foo" or :type => "bar" }
end
This results in an error. What is the proper way to handle this use case?
My actual case is using Paperclip to attach an image. I need to enforce the image is only .png or .jpg
class ValidateMe
validates_attachment :image,
presence => true,
:content_type => { :content_type => "image/png" }
end
Help with either code block is greatly appreciated. Thanks!
The best way to do this would be to pass an array of types to :content_type
class ValidateMe
validates_attachment :image,
presence => true,
:content_type => { :content_type => ['image/png', 'image/jpeg'] }
end
(My answer is based on code in Paperclip - Validate File Type but not Presence)
This can also be done using regular expressions. (Not as preferable)
class ValidateMe
validates_attachment :image,
presence => true,
:content_type => { :content_type => /^image\/(jpeg|png)$/ }
end
(source How can I restrict Paperclip to only accept images?)
I think Btuman's first answer would be considered canonical: The content_type key of content_type in validates_attachment can accept an array of valid content-types.
You can use :inclusion attribute for more see this http://guides.rubyonrails.org/active_record_validations_callbacks.html

How can I use variables within model?

I'm trying to insert the URL of the page into uploaded image.
I already have the code like this below but it doesn't work.
Is there something wrong in my model? How can I fix this?
My associations
User has_one :profile
Profile belongs_to :user
models/user.rb
before_save :text_to_insert?
def text_to_insert
nickname = self.profile.nickname
end
has_attached_file :user_avatar,
:styles => {
:thumb=> "100x100>",
:small => "400x400>" },
:convert_options => {
:small => '-fill white -undercolor "#00000080" -gravity South -annotate +0+5 " example.com/'+ nickname +' "' }
before saving , you are using text_to_insert? method which doesn't exist thatwhy it is returning false,so it fails to save .
It looks like typos ,try removing ? after :text_to_insert ie
before_save :text_to_insert
Please be sure that is valid self.profile.nickname

Image orientation and validation with Paperclip?

I'm looking for a way to determine image orientation preferably with Paperclip, but is it even possible or do I need to user RMagick or another image library for this?
Case scenario: When a user uploads an image i want to check the orientation/size/dimensions to determine if the image is in portrait/landscape or square and save this attribute to the model.
Here's what I generally do in my image models. Perhaps it will help:
I use IM's -auto-orient option when converting. This ensures images are always rotated properly after upload
I read the EXIF data after processing and get the width and height (among other things)
You can then just have an instance method that outputs an orientation string based on width and height
has_attached_file :attachment,
:styles => {
:large => "900x600>",
:medium => "600x400>",
:square => "100x100#",
:small => "300x200>" },
:convert_options => { :all => '-auto-orient' },
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:s3_permissions => 'public-read',
:s3_protocol => 'https',
:path => "images/:id_partition/:basename_:style.:extension"
after_attachment_post_process :post_process_photo
def post_process_photo
imgfile = EXIFR::JPEG.new(attachment.queued_for_write[:original].path)
return unless imgfile
self.width = imgfile.width
self.height = imgfile.height
self.model = imgfile.model
self.date_time = imgfile.date_time
self.exposure_time = imgfile.exposure_time.to_s
self.f_number = imgfile.f_number.to_f
self.focal_length = imgfile.focal_length.to_s
self.description = imgfile.image_description
end
Thanks for the answer jonnii.
Although I did find what I was looking for in the PaperClip::Geometry module.
This worked find:
class Image < ActiveRecord::Base
after_save :set_orientation
has_attached_file :data, :styles => { :large => "685x", :thumb => "100x100#" }
validates_attachment_content_type :data, :content_type => ['image/jpeg', 'image/pjpeg'], :message => "has to be in jpeg format"
private
def set_orientation
self.orientation = Paperclip::Geometry.from_file(self.data.to_file).horizontal? ? 'horizontal' : 'vertical'
end
end
This of course makes both vertical and square images have the vertical attribute but that's what I wanted anyway.
When I take a photo with my camera the dimensions of the image are the same regardless if the photo is landscape or portrait. However, my camera is smart enough to rotate the image for me! How thoughtful! The way this work is that is uses something called exif data which is meta data placed on the image by the camera. It includes stuff like: the type of camera, when the photo was taken, orientation etc...
With paperclip you can set up callbacks, specifically what you'll want to do is have a callback on before_post_process that checks the orientation of the image by reading the exif data using a library (you can find a list here: http://blog.simplificator.com/2008/01/14/ruby-and-exif-data/), and then rotating the image clockwise or counterclockwise 90 degrees (you won't know which way they rotated the camera when they took the photo).
I hope this helps!

Resources