state-machines / state_machines-activerecord

StateMachines Active Record Integration
https://github.com/state-machines/state_machines-activerecord
MIT License
401 stars 83 forks source link

Transient attributes quirks #93

Open boardfish opened 3 years ago

boardfish commented 3 years ago

I have a state machine on a class that inherits from ActiveRecord::Base that's something like this:

    state_machine :state do
      state :one, :two do
        validate { |record| record.validate_has_gubbins }
      end
      state :three

      event :one_to_two do
        transition one: :two # , if: ->(m) { m.gubbins.present? }
      end

      event :two_to_three do
        transition two: :three
      end
    end

It's based on an attribute that's not persisted to the database - a transient attribute. I define this with an attr_accessor and set its initial value in an after_initialize hook. The initial value is figured out from the current state of the record.

This is a useful approach because the state machine can be changed without a significant negative impact on existing records - if a new state were introduced between one and two, for example, two would still be stored in the database and would leave all two records in that state, whereas if it's dynamically figured out, they'd just move back to one with all data intact. It's just as useful for validating records at different stages while being a little more flexible where you need it.

There are a couple of quirks with this approach at the moment, though:

boardfish commented 3 years ago

I've since changed approaches - I'm now using a dynamic state machine as per the docs. Thus far, I think I'd recommend that, but I've got the following observations:

Tangentially related, but with transient attributes, use the ActiveRecord Attributes API.