跳过对状态机方法的所有验证



我试图弄清楚如何跳过对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

最新更新