# A reminder has a status and acts like a Finite State Machine. It uses the # Acts As State Machine plugin and operates like this: # # Send (recurring[t]) # +------+ # | | # v | # +-----------+ Send (recurring[f]) +-----------+ # | |---------------------->| | # -->| Pending | | Sent | # | |<----------------------| | # +-----------+ Reset +-----------+ # | ^ # | | # Pause v | Start # +-----------+ # | | # | Paused | # | | # +-----------+ # # # The only relevent part of the model to this example is a boolean flag marking # the reminder as recurring or not. When a recurring reminder is sent, its # time will be updated and it should be placed back in the pending queue. # # Here is the active record class with the AASM plugin: # class Reminder < ActiveRecord::Base # The reminder's start state is the pending status acts_as_state_machine :initial => :pending, :column => 'status' state :pending # Reminder is waiting to be sent state :sent # The reminder has been sent state :paused # Reminders in the paused state will not be sent even if # it is time to send them # The send event transitions the reminder from pending to sent, unless the # reminder is recurring. In that case, the reminder is left in the pending # state. event :send do transitions :to => :pending, :from => :pending, :guard => :recurring? transitions :to => :sent, :from => :pending end # The pause event transitions a reminder from pending to paused. It does not # make sense to transition from sent to paused, so that transition is ignored. event :pause do transitions :to => :paused, :from => :pending end # The start event transitions a reminder from paused to pending. It does not # make sense to transition from start to pending, so that transition is ignored. event :start do transitions :to => :pending, :from => :paused end # The reset event transitions a reminder from sent to pending. If a sent # reminder is updated with a new time, it should be reset to fire again. event :reset do transitions :to => :pending, :from => :sent end end # ############################################################################## # Usage Examples # ############################################################################## # Normal reminder r = Reminder.create r.current_state # => :pending # When the reminder is sent, fire the send event using the automatically # created method: r.send! r.current_state # => :sent r.sent? # => true r.update_attribute :send_on, Time.now + 7.days r.reset! r.current_state # => true # Recurring example r = Reminder.create(:recurring => true) r.current_state # => :pending # Pause delivery r.pause! r.current_state # => :paused r.paused? # => true # Invalid transitions are ignored r.send! r.current_state # => :paused # Start it again r.start! r.current_state # => :pending # Send it r.send! r.current_state # => :pending (it was recurring, remember)