# Migrating from _AASM_ version 3 to 4 ## Must ### Callback order has been changed The first callback to be run is `:before` of the event. A state's `:before_exit' callback is now run directly before its `:exit` callback. Event-based guards are now run before any of the transition guards are run. And finally, before running any state callbacks, all (event- and transition-based) guards are run to check whether the state callbacks can be run or not. ### `after_commit` hooks are now event-based The `after_commit` hooks have been move from the state level to the event level. So, if you want some code block to be executed after the _AASM_ state has been saved **AND** committed, change this code ```ruby class Job < ActiveRecord::Base include AASM aasm do state :sleeping, :initial => true state :running, :after_commit => :notify_about_running_job event :run do transitions :from => :sleeping, :to => :running end end def notify_about_running_job ... end end ``` to ```ruby class Job < ActiveRecord::Base include AASM aasm do state :sleeping, :initial => true state :running event :run, :after_commit => :notify_about_running_job do transitions :from => :sleeping, :to => :running end end def notify_about_running_job ... end end ``` ## Could ### Triggering an event without _to_state_ When providing parameters to callbacks it is not required to provide the `to_state` anymore. So, assuming you have the following class: ```ruby class Job include AASM aasm do state :sleeping, :initial => true state :running event :run do transitions :from => :sleeping, :to => :running, :after => :log end end def log(message) logger.info message end end ``` then you could change from ```ruby job = Job.new job.run(:running, "we want to run") ``` to this: ```ruby job = Job.new job.run("we want to run") job.run(:running, "we want to run") # still supported to select the target state (the _to_state_) ``` On the other hand, you have to accept the arguments for **all** callback methods (and procs) you provide and use. If you don't want to provide these, you can splat them ```ruby def before(*args); end # or def before(*_); end # to indicate that you don't want to use the arguments ``` ### New configuration option: `no_direct_assignment` If you want to make sure that the _AASM_ column for storing the state is not directly assigned, configure _AASM_ to not allow direct assignment, like this: ```ruby class Job < ActiveRecord::Base include AASM aasm :no_direct_assignment => true do state :sleeping, :initial => true state :running event :run do transitions :from => :sleeping, :to => :running end end end ``` resulting in this: ```ruby job = Job.create job.aasm_state # => 'sleeping' job.aasm_state = :running # => raises AASM::NoDirectAssignmentError job.aasm_state # => 'sleeping' ```