lib/aasm/persistence/mongoid_persistence.rb
require 'aasm/persistence/orm'
module AASM
module Persistence
module MongoidPersistence
# This method:
#
# * extends the model with ClassMethods
# * includes InstanceMethods
#
# Adds
#
# before_validation :aasm_ensure_initial_state
#
# As a result, it doesn't matter when you define your methods - the following 2 are equivalent
#
# class Foo
# include Mongoid::Document
# def aasm_write_state(state)
# "bar"
# end
# include AASM
# end
#
# class Foo
# include Mongoid::Document
# include AASM
# def aasm_write_state(state)
# "bar"
# end
# end
#
def self.included(base)
base.send(:include, AASM::Persistence::Base)
base.send(:include, AASM::Persistence::ORM)
base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
base.extend AASM::Persistence::MongoidPersistence::ClassMethods
base.after_initialize :aasm_ensure_initial_state
end
module ClassMethods
def aasm_create_scope(state_machine_name, scope_name)
scope_options = lambda {
send(
:where,
{ aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s }
)
}
send(:scope, scope_name, scope_options)
end
end
module InstanceMethods
private
def aasm_save
self.save
end
def aasm_raise_invalid_record
raise Mongoid::Errors::Validations.new(self)
end
def aasm_supports_transactions?
false
end
def aasm_update_column(attribute_name, value)
if Mongoid::VERSION.to_f >= 4
set(Hash[attribute_name, value])
else
set(attribute_name, value)
end
true
end
def aasm_read_attribute(name)
read_attribute(name)
end
def aasm_write_attribute(name, value)
write_attribute(name, value)
end
# Ensures that if the aasm_state column is nil and the record is new
# that the initial state gets populated before validation on create
#
# foo = Foo.new
# foo.aasm_state # => nil
# foo.valid?
# foo.aasm_state # => "open" (where :open is the initial state)
#
#
# foo = Foo.find(:first)
# foo.aasm_state # => 1
# foo.aasm_state = nil
# foo.valid?
# foo.aasm_state # => nil
#
def aasm_ensure_initial_state
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
attribute_name = self.class.aasm(state_machine_name).attribute_name.to_s
# Do not load initial state when object attributes are not loaded,
# mongoid has_many relationship does not load child object attributes when
# only ids are loaded, for example parent.child_ids will not load child object attributes.
# This feature is introduced in mongoid > 4.
if attribute_names.include?(attribute_name) && !attributes[attribute_name] || attributes[attribute_name].empty?
# attribute_missing? is defined in mongoid > 4
return if Mongoid::VERSION.to_f >= 4 && attribute_missing?(attribute_name)
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
end
end
end
end # InstanceMethods
# module NamedScopeMethods
# def aasm_state_with_named_scope name, options = {}
# aasm_state_without_named_scope name, options
# self.named_scope name, :conditions => { "#{table_name}.#{self.aasm.attribute_name}" => name.to_s} unless self.respond_to?(name)
# end
# end
end
end # Persistence
end # AASM