State Machine, Model Validations and RSpec

痴心易碎 提交于 2019-11-30 05:28:41

问题


Here's my current class definition and spec:

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

When I run the spec, I get two failures and one success. I have no idea why. For two of the states, the return if end_time.blank? statement in the end_time_before_final method evaluates to true when it should be false each time. 'postponed' is the only state that seems to pass. Any idea as to what might be happening here?


回答1:


It looks like you're running into a caveat noted in the documentation:

One important caveat here is that, due to a constraint in ActiveModel's validation framework, custom validators will not work as expected when defined to run in multiple states. For example:

 class Vehicle
   include ActiveModel::Validations

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

In this case, the :speed_is_legal validation will only get run for the :second_gear state. To avoid this, you can define your custom validation like so:

 class Vehicle
   include ActiveModel::Validations

   state_machine do
     ...
     state :first_gear, :second_gear do
       validate {|vehicle| vehicle.speed_is_legal}
     end
   end
 end


来源:https://stackoverflow.com/questions/10643997/state-machine-model-validations-and-rspec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!