开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜