Passing variables to Rails StateMachine gem transitions

大兔子大兔子 提交于 2019-12-03 01:52:32

If you are referring to the state_machine gem - https://github.com/pluginaweek/state_machine - then it supports arguments to events

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

I was having trouble with all of the other answers, and then I found that you can simply override the event in the class.

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

Just make sure to call "super" in your custom method

I don't think you can pass params to events with that gem, so maybe you could try storing the current_user on @car (temporarily) so that your audit callback can access it.

In controller

@car.driver = current_user

In callback

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

Or something along those lines.. :)

I used transactions, instead of updating the object and changing the state in one call. For example, in update action,

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

Another common pattern (see the state_machine docs) that saves you from having to pass variables between the controller and model is to dynamically define a state-checking method within the callback method. This wouldn't be very elegant in the example given above, but might be preferable in cases where the model needs to handle the same variable(s) in different states. For example, if you have 'crashed', 'stolen', and 'borrowed' states in your Car model, all of which can be associated with a responsible Person, you could have:

state :crashed, :stolen, :borrowed do
  def blameable?
    true
  end

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

Then in the controller, you can do something like:

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