How do I set a model instance as invalid after validations are run but before it's saved?
I have a standard act开发者_StackOverflow中文版ive record model with an attributes that is required:
class Sample < ActiveRecord::Base
has_many :colors
before_validation :grab_colors
validates_presence_of :size
validate :number_of_colors
private
def grab_colors
# grab x number of colors | x = size
end
def number_of_colors
self.errors.add("size","is to large.") if colors.count < size
end
end
My problem is that the grab_colors method requires the size attribute but performs a result that needs to be validated as well. In the case above size is used before it's presence is validated.
Can I set the instance as invalid and stop the save process after all validation have been made?
There are a few ways to do this, but they all involve rewriting grab_colors to perform the validates_presence_of check.
You're setting up a before_validation callback. Any callback that returns false will cancel the rest of the transaction. So you'll need to handle that case that makes grab_colors fail on your own. Essentially you're asking for something like this:
def grab_colors
unless size.blank?
# grab x number of colors | x = size
else
errors.add(:size, "cannot be empty.")
return false
end
end
This merges the your custom before_validation with validates_presence_of. When size doesn't exist grab_colors will set an error and return false, cancelling the remainder of the transaction, so your standard validations are never executed. From what you've mentioned the only time this fails is when size is unset.
You can also achieve your desired effect by having number_of_colors call grab_colors instead of calling grab_colors as a before_validation. However, you'll still need to tweak grab_colors to handle the failure case where size isn't defined.
I am assuming that you want the number_of_colors
method to run after the grab_colors
method. In that case I would recommend calling both methods in order from a validate
method.
def validate
unless size.blank?
grab_colors
number_of_colors
end
end
The validation of size is still handled by
validates_presence_of :size
But if you have size then grab_colors
and number_of_colors
run. Now you won't need these lines
before_validation :grab_colors
validate :number_of_colors
精彩评论