Немного опоздал на вечеринку здесь, но я исследовал эту проблему для себя и обнаружил, что гем, который я сейчас использую для управления моими машинами состояний ( state_machine от pluginaweek ), имеет несколько методов, которыесправиться с этой проблемой довольно хорошо.
При использовании с ActiveRecord (и я предполагаю, что и другие слои персистентности), он предоставляет метод #state_event=
, который принимает строковое представление события, которое вы хотели бы запустить,См. Документацию здесь .
# For example,
vehicle = Vehicle.create # => #<Vehicle id: 1, name: nil, state: "parked">
vehicle.state_event # => nil
vehicle.state_event = 'invalid'
vehicle.valid? # => false
vehicle.errors.full_messages # => ["State event is invalid"]
vehicle.state_event = 'ignite'
vehicle.valid? # => true
vehicle.save # => true
vehicle.state # => "idling"
vehicle.state_event # => nil
# Note that this can also be done on a mass-assignment basis:
vehicle = Vehicle.create(:state_event => 'ignite') # => #<Vehicle id: 1, name: nil, state: "idling">
vehicle.state # => "idling"
Это позволяет просто добавить поле state_event
в формы редактирования вашего ресурса и получить переходы состояния так же легко, как обновить любой другой атрибут.
Теперь мы, очевидно, все еще используем PUT для запуска событий, используя этот метод, который не является RESTful.Драгоценный камень, однако, предоставляет интересный пример , который по крайней мере "чувствует" довольно RESTful, несмотря на то, что он использует тот же не-RESTful метод под прикрытием.
Как вы можете видеть здесь и здесь , возможности самоанализа камня позволяют вам представить в ваших формах либо событие, которое вы хотели бы запустить , либо имя результирующего состояния этого события.
<div class="field">
<%= f.label :state %><br />
<%= f.collection_select :state_event, @user.state_transitions, :event, :human_to_name, :include_blank => @user.human_state_name %>
</div>
<div class="field">
<%= f.label :access_state %><br />
<%= f.collection_select :access_state_event, @user.access_state_transitions, :event, :human_event, :include_blank => "don't change" %>
</div>
Используя последний метод, вы получаете простое обновление состояния модели на основе форм до любого допустимого следующего состояния без необходимости писать дополнительный код.Технически это не RESTful, но позволяет легко представить его в пользовательском интерфейсе.
Чистота этого метода в сочетании с внутренними конфликтами при попытке преобразовать конечный автомат, основанный на событиях, в простой ресурс RESTful был достаточным, чтобы удовлетворить меня, так что, надеюсь, он также даст вам некоторое представление.