将变量传递给Rails StateMachine gem过渡

是否可以在转换中发送变量? 即

@car.crash!(:crashed_by => current_user) 

我在我的模型中有回调,但我需要向他们发送启动过渡的用户

 after_crash do |car, transition| # Log the car crashers name end 

我无法访问current_user,因为我在模型中而不是Controller / View。

在你说之前……我知道我知道。

不要尝试访问模型中的会话变量

我知道了。

但是,每当您希望创建一个记录或审核某些内容的回调时,您很可能想知道是谁造成的? 通常,我的控制器中有一些东西像…

 @foo.some_method(current_user) 

我的Foo模型会期望一些用户发起some_method但是我如何通过StateMachine gem转换呢?

如果您指的是state_machine gem – https://github.com/pluginaweek/state_machine – 那么它支持事件的参数

 after_crash do |car, transition| Log.crash(:car => car, :driver => transition.args.first) end 

我遇到了所有其他答案的麻烦,然后我发现你可以简单地覆盖课堂上的事件。

 class Car state_machine do ... event :crash do transition any => :crashed end end def crash(current_driver) logger.debug(current_driver) super end end 

只需确保在自定义方法中调用“super”

我不认为您可以将params传递给具有该gem的事件,因此您可以尝试将current_user存储在@car(临时)上,以便您的审计回调可以访问它。

在控制器中

 @car.driver = current_user 

在回调中

 after_crash do |car, transition| create_audit_log car.driver, transition end 

或类似的规定.. :)

我使用了事务,而不是更新对象并在一次调用中更改状态。 例如,在更新操作中,

 ActiveRecord::Base.transaction do if @car.update_attribute!(:crashed_by => current_user) if @car.crash!() format.html { redirect_to @car } else raise ActiveRecord::Rollback else raise ActiveRecord::Rollback end end 

另一种常见模式(参见state_machine文档 )可以使您不必在控制器和模型之间传递变量,这是在回调方法中动态定义状态检查方法。 在上面给出的示例中,这不会非常优雅,但在模型需要处理不同状态的相同变量的情况下可能更为优雅。 例如,如果您的Car模型中有“崩溃”,“被盗”和“借入”状态,所有这些状态都可以与负责人联系在一起,您可以:

 state :crashed, :stolen, :borrowed do def blameable? true end state all - [:crashed, :stolen, :borrowed] do def blameable? false end 

然后在控制器中,您可以执行以下操作:

 car.blame_person(person) if car.blameable?