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

时间:2014-08-21 19:37:00

标签: ruby-on-rails ruby state-machine

当我的预订模型通过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

2 个答案:

答案 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)

这将触发您在状态机中定义的所有回调,这个解决方案对我来说效果很好。