Conditional Validation with Paperclip difficult - ruby-on-rails

I have an "item", which goes through a multi-page creation process. Images are uploaded at step five, and I keep track of the steps by using the attribute "complete". When validating whether an image is attached with paperclip, I get problems using the code below:
validates_attachment_presence :pic1, :if => Proc.new { |u| u.complete == "step5"}
It seems that I can't access the "complete" attribute, as the active-record object seems to be the paperclip image. Is there a way for me to check at which point in the process I am and validate conditionally?
Thanks,
Michael

How about
validates_attachment_presence :pic1, :if => 'complete == "setp5"?'
or
validates_attachment_presence :pic1, :if => :is_step5?
def is_step5?
self.complete == "step5"
end

Related

rails 3.2 skip paperclip attachment presence validation on edit action

I am new to Rails and i'm working on my first rails application that uses paperclip for attachments and i'm validating the presence of attachment using validates_attachment :avatar, presence: true which is working perfectly well on create action, but when a user is editing his account settings and doesn't upload a new avatar, there is an error for not having avatar uploaded but i want to skip that validation on edit and only validate on edit if user uploads a new one to replace existing one.
i also have
validates_format_of :avatar, :with => %r{\.(jpg|jpeg|gif|png)$}i,:unless => Proc.new {|m| m[:avatar].nil?}, :message => "Please upload files with the following extensions only
to check format only if present but doesn't seem to be working either
your help would be very much appreciated.
thanks
Use on option.
validates_format_of :avatar ... , :on => :create
http://guides.rubyonrails.org/v2.3.11/activerecord_validations_callbacks.html#on

Custom Paperclip processor not being called

I have a user model that is generated using Devise. I am extending this model using paperclip to enable file upload and also the processing of a file using a custom paperclip processor.
My paperclip field is declared in the user model as follows. PaperClipStorage is a hash that I create with the paperclip variables. Also, the being stored on AWS S3.
has_attached_file :rb_resume, PaperclipStorageHash.merge(:style => { :contents => 'resume_contents'}, :processors => [:resume_builder])
validates_attachment_content_type :rb_resume, :if => lambda { |x| x.rb_resume? }, :content_type => ['application/pdf', 'application/x-pdf', 'application/msword', 'application/x-doc']
The validates_attachment_content_type check is being done to make sure that it only processes pdf and MS word files.
My processor looks as follows
module Paperclip
class ResumeBuilder < Processor
def initialize(file,options = {}, attachment = nil)
#file = file
#attachment = attachment
puts "Attachment is not null " if !attachment.nil?
end
def make
rb = MyModule::MyClass.new(#file.path) ### Do something with the file
section_layout = rb.parse_html
#attachment.instance_write(:whiny, section_layout)
#file
end
end
end
In my user model I also have an after_save callback that is supposed to take the section_layout generated in the processors make method. Code is as follows
after_save :save_sections
def save_sections
section_layout = rb_resume.instance_read(:whiny)
# Do something with section_layout...
end
Now my problem is that the processor code is never being called, and I can't figure out why.
Because of that the section_layout variable is always nil.
Another point to note is that the same model also has two other has_attached_file attributes. None of the other two use a custom processor.
I've been struggling with this for last 3 hours. Any help would be greatly appreciate.
Thanks
Paul
Error in my has_attached_file declaration
has_attached_file :rb_resume, PaperclipStorageHash.merge(:style => { :contents => 'resume_contents'}, :processors => [:resume_builder])
should actually be
has_attached_file :rb_resume, PaperclipStorageHash.merge(:styles => { :contents => 'resume_contents'}, :processors => [:resume_builder])
Notice the plural styles as opposed to singular style

rails custom validation on action

I would like to know if there's a way to use rails validations on a custom action.
For example I would like do something like this:
validates_presence_of :description, :on => :publish, :message => "can't be blank"
I do basic validations create and save, but there are a great many things I don't want to require up front. Ie, they should be able to save a barebones record without validating all the fields, however I have a custom "publish" action and state in my controller and model that when used should validate to make sure the record is 100%
The above example didn't work, any ideas?
UPDATE:
My state machine looks like this:
include ActiveRecord::Transitions
state_machine do
state :draft
state :active
state :offline
event :publish do
transitions :to => :active, :from => :draft, :on_transition => :do_submit_to_user, :guard => :validates_a_lot?
end
end
I found that I can add guards, but still I'd like to be able to use rails validations instead of doing it all on a custom method.
That looks more like business logic rather than model validation to me. I was in a project a few years ago in which we had to publish articles, and lots of the business rules were enforced just at that moment.
I would suggest you to do something like Model.publish() and that method should enforce all the business rules in order for the item to be published.
One option is to run a custom validation method, but you might need to add some fields to your model. Here's an example - I'll assume that you Model is called article
Class Article < ActiveRecord::Base
validate :ready_to_publish
def publish
self.published = true
//and anything else you need to do in order to mark an article as published
end
private
def ready_to_publish
if( published? )
//checks that all fields are set
errors.add(:description, "enter a description") if self.description.blank?
end
end
end
In this example, the client code should call an_article.publish and when article.save is invoked it will do the rest automatically. The other big benefit of this approach is that your model will always be consistent, rather than depending on which action was invoked.
If your 'publish' action sets some kind of status field to 'published' then you could do:
validates_presence_of :description, :if => Proc.new { |a| a.state == 'published' }
or, if each state has its own method
validates_presence_of :description, :if => Proc.new { |a| a.published? }

Smarter paperclip validations

I'm using paperclip in a rails app and have the following three validations in my model
validates_attachment_presence :photo
validates_attachment_size :photo, :less_than=>1.megabyte
validates_attachment_content_type :photo, :content_type=>['image/jpeg', 'image/png', 'image/gif']
If the user forgets to add an attachment, all three validations fail and thus, the user is presented with the following three errors:
# Photo file name must be set.
# Photo file size file size must be between 0 and 1048576 bytes.
# Photo content type is not included in the list
I think it would be best to just show the first error in this instance since the other two errors are purely consequential... I would prefer the user to only ever see the second two errors if an attachment has been added but doesn't meet the validation criteria.
I'm certain there is no pre-baked validation that does this sort of thing and from reading the code in vendor/plugins/paperclip/lib/paperclip.rb I see that the validates_attachment_size method supports the :unless parameter as shown:
def validates_attachment_presence name, options = {}
message = options[:message] || "must be set."
validates_presence_of :"#{name}_file_name",
:message => message,
:if => options[:if],
:unless => options[:unless]
end
So, I was thinking that I could do something like the following:
validates_attachment_size :photo, :less_than=>1.megabyte, :unless=> :photo.blank
But that breaks the app. Anyone have any experience of doing this sort of thing? Would be a nice contribution to the paperclip source code.
EDIT:
I've tried using this:
validates_attachment_size :photo, :less_than=>1.megabyte,
:unless=> Proc.new { |image| image[:photo].nil? }
It doesn't quite work though as I've just managed to upload a 5mb mp3 with this validation in place. But it's promising as the error message doesn't appear when the user has not attached a photo.
validates_attachment_size :photo, :less_than => 1.megabyte,
:unless => Proc.new { |imports| imports.photo_file_name.blank? }
I think you can do it other way. Don't mess with validations. You probably have something like this in your form:
<%= f.error_messages %>
You can remove it and write your own helper to display error messages. Errors are stored in hash:
#photo.errors
Or if you want to get to them through form builder:
f.object.errors

Ruby on Rails ActiveRecord conditional validation (and more..)

I have a Product model which validates multiple attributes (including a Paperclip image attachment) like so:
validates_presence_of :name
validates_format_of :name, :with => /^([a-zA-Z0-9\ \-]{3,128})$/i
...
has_attached_file :image
validates_attachment_presence :image
validates_attachment_content_type :image, :content_type => ["image/jpeg", "image/png", "image/gif"]
Everything is working fine. What I want now is to make an (unobtrusive) hidden iframe in-place upload script using javascript. My problem is that I cannot just upload the image without the rest of the data, because it will fail validation (no name present) and also I cannot send the rest of the form without the image (same thing, fails validation).
So basically what I need (and don't know how to achieve) is to conditionally apply the model validations according to what the action is currently in progress (uploading the image or editing other data).
I hope I was clear enough. Any help is appreciated. Thanks.
Railscasts have a nice video screencast about conditional validations.
I hate having to wade through a video just to get a simple answer. In fact, I think that a blog entry is superior to a simple tutorial video simply for the fact that it is searchable. Here is a simple case in plain text for anyone else looking:
To validate the presence of password only for the create action, do this:
validates_presence_of :password, :on => :create
A comment for Peter D.
Thank you very much. I'm unable to watch that screen cast presently (though I plan to) and was looking for a speedy, brief answer.
Incorporated your suggestion into a model I have and it's working perfectly. (Though I suspect at some point I'm going to need validation on update when passwords are being changed. I'll take it as "technical debt" now though, in order to move on.)
The bit I added:
validates :password, :presence => true, :confirmation => true, :on => :create

Resources