我来晚了,但是我正在为自己研究这个确切的问题,发现我目前使用来管理状态机的gem(pluginaweek的state_machine)有一些方法可以很好地处理这个问题。
当与ActiveRecord(我假设其他持久层也是如此)一起使用时,它提供了一个#state_event=
方法,接受一个事件的字符串表示形式,您想要触发。请参见此处的文档。
vehicle = Vehicle.create
vehicle.state_event
vehicle.state_event = 'invalid'
vehicle.valid?
vehicle.errors.full_messages
vehicle.state_event = 'ignite'
vehicle.valid?
vehicle.save
vehicle.state
vehicle.state_event
vehicle = Vehicle.create(:state_event => 'ignite')
vehicle.state
这使您可以在资源的编辑表单中简单地添加一个
state_event
字段,并像更新任何其他属性一样轻松地获取状态转换。现在,显然仍然使用PUT来触发事件,这不是符合RESTful标准的。然而,该gem提供了
一个有趣的例子,即使在底层使用相同的非RESTful方法,它至少“感觉”相当符合RESTful标准。正如您可以在
这里和
这里看到的那样,该gem的内省能力允许您在表单中呈现要触发的事件或该事件结果状态的名称。
<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,但它允许您在UI中轻松地呈现它。这种技术的简洁性以及尝试将基于事件的状态机转换为简单的RESTful资源时固有的冲突足以满足我,希望它也能为您提供一些见解。