我试图弄清楚如何跳过对ActiveRecord对象的特定实例的验证,当我的保留模型通过rake任务在状态机上转换时。当reservation.close时,我想跳过所有验证!被称为。我希望能打个预订之类的电话。(:validate => false)。供参考,我们使用https://github.com/pluginaweek/state_machine作为状态机。
这是我的预订模型的样本。
class Reservation < ActiveRecord::Base
validates :ride_id, :start_at, :end_at, presence: true
validate :proper_custom_price?, allow_nil: true, on: :update
validate :dates_valid?
validate :dates_make_sense?
scope :needs_close_transition, lambda { where("end_at < ?", Time.now).where("state" => ["requested", "negotiating", "approved"]) }
state_machine :initial => 'requested' do
all_prebooked = ["requested", "negotiating", "approved"]
event :close do
transition :from => all_prebooked,
:to => "precanceled"
end
before_transition :on => [:close] do |reservation|
reservation.cancel_reason = :admin
end
end
end
这是我的rake任务的一个示例。
namespace :reservation do
task :close => :environment do
puts "== close"
Reservation.needs_close_transition.each do |reservation|
puts "===> #{reservation.id}"
begin
reservation.close!(:validate => false)
rescue Exception => e
Airbrake.notify(e, error_message: e.message) if defined?(Airbrake)
end
end
end
我有同样的问题,但是我不想改变我当前的验证,所以我检查了状态机代码(版本1.2.0),我找到了另一个解决方案,对于您的具体情况,它将是类似的:
reservation.close!(false)
reservation.save(validate: false)
这将触发您在状态机中定义的所有回调,并且这个解决方案对我来说工作得很好。
当使用state_machine gem时,state
属性在验证运行之前被更新,因此您可以在验证中添加一个unless条件来测试当前状态:
validates :start_at, :end_at, presence: true, unless: Proc.new {state == 'closed'}
如果你想要更复杂的逻辑,传递一个方法名symbox给unless
,而不是一个进程:
validates :start_at, :end_at, presence: true, unless: :requires_validation?
def requires_validation?
# complex logic to determine if the record should be validated
end