Passing variables to Rails StateMachine gem transitions

前端 未结 5 2137
猫巷女王i
猫巷女王i 2021-02-05 10:07

Is it possible to send variables in the the transition? i.e.

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

I have callbacks in my model but I nee

相关标签:
5条回答
  • 2021-02-05 10:46

    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
    
    0 讨论(0)
  • 2021-02-05 10:57

    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

    0 讨论(0)
  • 2021-02-05 10:59

    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.. :)

    0 讨论(0)
  • 2021-02-05 10:59

    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?
    
    0 讨论(0)
  • 2021-02-05 11:03

    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
    
    0 讨论(0)
提交回复
热议问题