当我的预订模型通过rake任务在状态机上转换时,我试图弄清楚如何跳过ActiveRecord对象的特定实例上的验证。我想在reservation.close时跳过所有验证!叫做。希望打电话给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
以下是我的佣金任务示例。
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
答案 0 :(得分:4)
使用state_machine gem时,state
属性会在运行验证之前更新,因此您可以将except条件添加到测试当前状态的验证中:
validates :start_at, :end_at, presence: true, unless: Proc.new {state == 'closed'}
如果您想要更复杂的逻辑,请将方法名称symbox传递给unless
而不是proc:
validates :start_at, :end_at, presence: true, unless: :requires_validation?
def requires_validation?
# complex logic to determine if the record should be validated
end
答案 1 :(得分:4)
我有同样的问题,但是我不想改变我当前的验证,所以我检查了状态机代码(版本1.2.0),我发现了另一个解决方案,对于你的特定情况,它会是这样的: / p>
reservation.close!(false)
reservation.save(validate: false)
这将触发您在状态机中定义的所有回调,这个解决方案对我来说效果很好。