2008-02-22 15:46:31 -05:00
|
|
|
module AASM
|
|
|
|
module Persistence
|
|
|
|
module ActiveRecordPersistence
|
2008-04-29 01:27:56 -04:00
|
|
|
# This method:
|
|
|
|
#
|
|
|
|
# * extends the model with ClassMethods
|
|
|
|
# * includes InstanceMethods
|
|
|
|
#
|
|
|
|
# Unless the corresponding methods are already defined, it includes
|
|
|
|
# * ReadState
|
|
|
|
# * WriteState
|
|
|
|
# * WriteStateWithoutPersistence
|
|
|
|
#
|
|
|
|
# As a result, it doesn't matter when you define your methods - the following 2 are equivalent
|
|
|
|
#
|
|
|
|
# class Foo < ActiveRecord::Base
|
|
|
|
# def aasm_write_state(state)
|
|
|
|
# "bar"
|
|
|
|
# end
|
|
|
|
# include AASM
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# class Foo < ActiveRecord::Base
|
|
|
|
# include AASM
|
|
|
|
# def aasm_write_state(state)
|
|
|
|
# "bar"
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
2008-02-22 15:46:31 -05:00
|
|
|
def self.included(base)
|
|
|
|
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
|
2008-04-29 01:27:56 -04:00
|
|
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
2008-02-22 15:46:31 -05:00
|
|
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::ReadState) unless base.method_defined?(:aasm_read_state)
|
2008-04-29 01:27:56 -04:00
|
|
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
|
|
|
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
|
2008-02-22 15:46:31 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
module ClassMethods
|
2008-04-29 01:27:56 -04:00
|
|
|
# Maps to the aasm_column in the database. Deafults to "aasm_state". You can write:
|
|
|
|
#
|
|
|
|
# create_table :foos do |t|
|
|
|
|
# t.string :name
|
|
|
|
# t.string :aasm_state
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# class Foo < ActiveRecord::Base
|
|
|
|
# include AASM
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# OR:
|
|
|
|
#
|
|
|
|
# create_table :foos do |t|
|
|
|
|
# t.string :name
|
|
|
|
# t.string :status
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# class Foo < ActiveRecord::Base
|
|
|
|
# include AASM
|
|
|
|
# aasm_column :status
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# This method is both a getter and a setter
|
2008-02-22 15:46:31 -05:00
|
|
|
def aasm_column(column_name=nil)
|
|
|
|
if column_name
|
|
|
|
@aasm_column = column_name.to_sym
|
|
|
|
else
|
2008-02-27 15:32:52 -05:00
|
|
|
@aasm_column ||= :aasm_state
|
2008-02-22 15:46:31 -05:00
|
|
|
end
|
2008-04-29 01:27:56 -04:00
|
|
|
@aasm_column
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
module InstanceMethods
|
|
|
|
|
|
|
|
# Returns the current aasm_state of the object. Respects reload and
|
|
|
|
# any changes made to the aasm_state field directly
|
|
|
|
#
|
|
|
|
# Internally just calls <tt>aasm_read_state</tt>
|
|
|
|
#
|
|
|
|
# foo = Foo.find(1)
|
|
|
|
# foo.aasm_current_state # => :pending
|
|
|
|
# foo.aasm_state = "opened"
|
|
|
|
# foo.aasm_current_state # => :opened
|
|
|
|
# foo.close # => calls aasm_write_state_without_persistence
|
|
|
|
# foo.aasm_current_state # => :closed
|
|
|
|
# foo.reload
|
|
|
|
# foo.aasm_current_state # => :pending
|
|
|
|
#
|
|
|
|
def aasm_current_state
|
|
|
|
@current_state = aasm_read_state
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
module WriteStateWithoutPersistence
|
|
|
|
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
|
|
|
#
|
|
|
|
# foo = Foo.find(1)
|
|
|
|
# foo.aasm_current_state # => :opened
|
|
|
|
# foo.close
|
|
|
|
# foo.aasm_current_state # => :closed
|
|
|
|
# Foo.find(1).aasm_current_state # => :opened
|
|
|
|
# foo.save
|
|
|
|
# foo.aasm_current_state # => :closed
|
|
|
|
# Foo.find(1).aasm_current_state # => :closed
|
|
|
|
#
|
|
|
|
# NOTE: intended to be called from an event
|
|
|
|
def aasm_write_state_without_persistence(state)
|
|
|
|
write_attribute(self.class.aasm_column, state.to_s)
|
2008-02-22 15:46:31 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module WriteState
|
2008-04-29 01:27:56 -04:00
|
|
|
# Writes <tt>state</tt> to the state column and persists it to the database
|
|
|
|
# using update_attribute (which bypasses validation)
|
|
|
|
#
|
|
|
|
# foo = Foo.find(1)
|
|
|
|
# foo.aasm_current_state # => :opened
|
|
|
|
# foo.close!
|
|
|
|
# foo.aasm_current_state # => :closed
|
|
|
|
# Foo.find(1).aasm_current_state # => :closed
|
|
|
|
#
|
|
|
|
# NOTE: intended to be called from an event
|
2008-02-22 15:46:31 -05:00
|
|
|
def aasm_write_state(state)
|
2008-02-27 15:32:52 -05:00
|
|
|
update_attribute(self.class.aasm_column, state.to_s)
|
2008-02-22 15:46:31 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module ReadState
|
2008-04-29 01:27:56 -04:00
|
|
|
|
|
|
|
# Returns the value of the aasm_column - called from <tt>aasm_current_state</tt>
|
|
|
|
#
|
|
|
|
# If it's a new record, and the aasm state column is blank it returns the initial state:
|
|
|
|
#
|
|
|
|
# class Foo < ActiveRecord::Base
|
|
|
|
# include AASM
|
|
|
|
# aasm_column :status
|
|
|
|
# aasm_state :opened
|
|
|
|
# aasm_state :closed
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# foo = Foo.new
|
|
|
|
# foo.current_state # => :opened
|
|
|
|
# foo.close
|
|
|
|
# foo.current_state # => :closed
|
|
|
|
#
|
|
|
|
# foo = Foo.find(1)
|
|
|
|
# foo.current_state # => :opened
|
|
|
|
# foo.aasm_state = nil
|
|
|
|
# foo.current_state # => nil
|
|
|
|
#
|
|
|
|
# NOTE: intended to be called from an event
|
|
|
|
#
|
|
|
|
# This allows for nil aasm states - be sure to add validation to your model
|
2008-02-22 15:46:31 -05:00
|
|
|
def aasm_read_state
|
2008-04-29 01:27:56 -04:00
|
|
|
if new_record?
|
|
|
|
send(self.class.aasm_column).blank? ? self.class.aasm_initial_state : send(self.class.aasm_column).to_sym
|
|
|
|
else
|
|
|
|
send(self.class.aasm_column).nil? ? nil : send(self.class.aasm_column).to_sym
|
|
|
|
end
|
2008-02-22 15:46:31 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|