5

これが私の現在のクラス定義と仕様です:

class Event < ActiveRecord::Base

  # ...

  state_machine :initial => :not_started do

    event :game_started do
      transition :not_started => :in_progress
    end

    event :game_ended do
      transition :in_progress => :final
    end

    event :game_postponed do
      transition [:not_started, :in_progress] => :postponed
    end

    state :not_started, :in_progress, :postponed do
      validate :end_time_before_final
    end
  end

  def end_time_before_final
    return if end_time.blank?
    errors.add :end_time, "must be nil until event is final" if end_time.present?
  end

end

describe Event do
  context 'not started, in progress or postponed' do
    describe '.end_time_before_final' do
      ['not_started', 'in_progress', 'postponed'].each do |state|
        it 'should not allow end_time to be present' do
          event = Event.new(state: state, end_time: Time.now.utc)
          event.valid?
          event.errors[:end_time].size.should == 1
          event.errors[:end_time].should == ['must be nil until event is final']
        end
      end
    end
  end
end

スペックを実行すると、2つの失敗と1つの成功が発生します。理由はわかりません。2つの状態の場合return if end_time.blank?、メソッドのステートメントは、end_time_before_final毎回falseである必要があるときにtrueと評価されます。「延期」は、通過するように見える唯一の状態です。ここで何が起こっているのかについて何か考えはありますか?

4

1 に答える 1

13

ドキュメントに記載されている警告に遭遇しているようです:

ここでの重要な注意点の1つは、ActiveModelの検証フレームワークの制約により、複数の状態で実行するように定義されている場合、カスタムバリデーターが期待どおりに機能しないことです。例えば:

 class Vehicle
   include ActiveModel::Validations

   state_machine do
     ...
     state :first_gear, :second_gear do
       validate :speed_is_legal
     end
   end
 end

この場合、:speed_is_legal検証は:second_gear状態でのみ実行されます。これを回避するには、次のようにカスタム検証を定義できます。

 class Vehicle
   include ActiveModel::Validations

   state_machine do
     ...
     state :first_gear, :second_gear do
       validate {|vehicle| vehicle.speed_is_legal}
     end
   end
 end
于 2012-05-20T09:16:22.317 に答える