1
0
Fork 0
mirror of https://github.com/aasm/aasm synced 2023-03-27 23:22:41 -04:00

no need for WriteState mixin anymore (to keep adding persistence simple)

This commit is contained in:
Thorsten Böttger 2013-04-24 13:51:21 +02:00
parent 52181d8017
commit 95ef7fc834
8 changed files with 151 additions and 102 deletions

10
API
View file

@ -7,3 +7,13 @@ Overwrite method to read the current state
# retrieve the current state manually # retrieve the current state manually
end end
end end
Overwrite method to write the current state
class MyClass
include AASM
def aasm_write_state
# store the current state manually
end
end

View file

@ -86,6 +86,11 @@ module AASM
aasm.enter_initial_state aasm.enter_initial_state
end end
# may be overwritten by persistence mixins
def aasm_write_state(new_state)
true
end
# deprecated # deprecated
def aasm_current_state def aasm_current_state
# warn "#aasm_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.state instead!" # warn "#aasm_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.state instead!"

View file

@ -69,10 +69,7 @@ module AASM
end end
def set_current_state_with_persistence(state) def set_current_state_with_persistence(state)
save_success = true
if @instance.respond_to?(:aasm_write_state) || @instance.private_methods.include?('aasm_write_state')
save_success = @instance.aasm_write_state(state) save_success = @instance.aasm_write_state(state)
end
self.current_state = state if save_success self.current_state = state if save_success
save_success save_success
end end

View file

@ -7,7 +7,6 @@ module AASM
# * includes InstanceMethods # * includes InstanceMethods
# #
# Unless the corresponding methods are already defined, it includes # Unless the corresponding methods are already defined, it includes
# * WriteState
# * WriteStateWithoutPersistence # * WriteStateWithoutPersistence
# #
# Adds # Adds
@ -34,7 +33,6 @@ module AASM
base.send(:include, AASM::Persistence::Base) base.send(:include, AASM::Persistence::Base)
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods) base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
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) base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
if ActiveRecord::VERSION::MAJOR >= 3 if ActiveRecord::VERSION::MAJOR >= 3
@ -74,6 +72,32 @@ module AASM
module InstanceMethods module InstanceMethods
# Writes <tt>state</tt> to the state column and persists 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 # => :closed
#
# NOTE: intended to be called from an event
def aasm_write_state(state)
old_value = read_attribute(self.class.aasm_column)
write_attribute(self.class.aasm_column, state.to_s)
success = if AASM::StateMachine[self.class].config.skip_validation_on_save
self.class.update_all({ self.class.aasm_column => state.to_s }, self.class.primary_key => self.id) == 1
else
self.save
end
unless success
write_attribute(self.class.aasm_column, old_value)
return false
end
true
end
private private
# Ensures that if the aasm_state column is nil and the record is new # Ensures that if the aasm_state column is nil and the record is new
@ -100,8 +124,7 @@ module AASM
super super
end end
end end
end # InstanceMethods
end
module WriteStateWithoutPersistence module WriteStateWithoutPersistence
# Writes <tt>state</tt> to the state column, but does not persist it to the database # Writes <tt>state</tt> to the state column, but does not persist it to the database
@ -121,34 +144,6 @@ module AASM
end end
end end
module WriteState
# Writes <tt>state</tt> to the state column and persists 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 # => :closed
#
# NOTE: intended to be called from an event
def aasm_write_state(state)
old_value = read_attribute(self.class.aasm_column)
write_attribute(self.class.aasm_column, state.to_s)
success = if AASM::StateMachine[self.class].config.skip_validation_on_save
self.class.update_all({ self.class.aasm_column => state.to_s }, self.class.primary_key => self.id) == 1
else
self.save
end
unless success
write_attribute(self.class.aasm_column, old_value)
return false
end
true
end
end
end end
end end
end end

View file

@ -7,7 +7,6 @@ module AASM
# * includes InstanceMethods # * includes InstanceMethods
# #
# Unless the corresponding methods are already defined, it includes # Unless the corresponding methods are already defined, it includes
# * WriteState
# * WriteStateWithoutPersistence # * WriteStateWithoutPersistence
# #
# Adds # Adds
@ -36,7 +35,6 @@ module AASM
base.send(:include, AASM::Persistence::Base) base.send(:include, AASM::Persistence::Base)
base.extend AASM::Persistence::MongoidPersistence::ClassMethods base.extend AASM::Persistence::MongoidPersistence::ClassMethods
base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods) base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
base.send(:include, AASM::Persistence::MongoidPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
base.send(:include, AASM::Persistence::MongoidPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence) base.send(:include, AASM::Persistence::MongoidPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
# Mongoid's Validatable gem dependency goes not have a before_validation_on_xxx hook yet. # Mongoid's Validatable gem dependency goes not have a before_validation_on_xxx hook yet.
@ -68,48 +66,6 @@ module AASM
module InstanceMethods module InstanceMethods
private
# 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
send("#{self.class.aasm_column}=", aasm.enter_initial_state.to_s) if send(self.class.aasm_column).blank?
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)
end
end
module WriteState
# Writes <tt>state</tt> to the state column and persists it to the database # Writes <tt>state</tt> to the state column and persists it to the database
# using update_attribute (which bypasses validation) # using update_attribute (which bypasses validation)
# #
@ -131,6 +87,45 @@ module AASM
true true
end end
private
# 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
send("#{self.class.aasm_column}=", aasm.enter_initial_state.to_s) if send(self.class.aasm_column).blank?
end
end # InstanceMethods
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)
end
end end
module NamedScopeMethods module NamedScopeMethods

View file

@ -1,43 +1,67 @@
class DefaultState class DefaultState
attr_accessor :transient_store
include AASM include AASM
aasm do aasm do
state :alpha, :initial => true state :alpha, :initial => true
state :beta state :beta
state :gamma state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end end
end end
class ProvidedState class ProvidedState
attr_accessor :transient_store
include AASM include AASM
aasm do aasm do
state :alpha, :initial => true state :alpha, :initial => true
state :beta state :beta
state :gamma state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end end
def aasm_read_state def aasm_read_state
:beta :beta
end end
def aasm_write_state(new_state)
@transient_store = new_state
end
end end
class PersistedState < ActiveRecord::Base class PersistedState < ActiveRecord::Base
attr_accessor :transient_store
include AASM include AASM
aasm do aasm do
state :alpha, :initial => true state :alpha, :initial => true
state :beta state :beta
state :gamma state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end end
end end
class ProvidedAndPersistedState < ActiveRecord::Base class ProvidedAndPersistedState < ActiveRecord::Base
attr_accessor :transient_store
include AASM include AASM
aasm do aasm do
state :alpha, :initial => true state :alpha, :initial => true
state :beta state :beta
state :gamma state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end end
def aasm_read_state def aasm_read_state
:gamma :gamma
end end
def aasm_write_state(new_state)
@transient_store = new_state
end
end end

View file

@ -1,7 +1,7 @@
require 'spec_helper' require 'spec_helper'
require 'models/active_record/api.rb' require 'models/active_record/api.rb'
describe "retrieving the current state" do describe "reading the current state" do
it "uses the AASM default" do it "uses the AASM default" do
DefaultState.new.aasm.current_state.should eql :alpha DefaultState.new.aasm.current_state.should eql :alpha
end end
@ -18,3 +18,29 @@ describe "retrieving the current state" do
ProvidedAndPersistedState.new.aasm.current_state.should eql :gamma ProvidedAndPersistedState.new.aasm.current_state.should eql :gamma
end end
end end
describe "writing the current state" do
it "uses the AASM default" do
o = DefaultState.new
o.release!
o.transient_store.should be_nil
end
it "uses the provided method" do
o = ProvidedState.new
o.release!
o.transient_store.should eql :beta
end
it "uses the persistence storage" do
o = PersistedState.new
o.release!
o.transient_store.should be_nil
end
it "uses the provided method even if persisted" do
o = ProvidedAndPersistedState.new
o.release!
o.transient_store.should eql :beta
end
end

View file

@ -18,7 +18,6 @@ describe "class methods for classes without own read or write state" do
let(:klass) {Gate} let(:klass) {Gate}
it_should_behave_like "aasm model" it_should_behave_like "aasm model"
it "should include all persistence mixins" do it "should include all persistence mixins" do
klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
end end
end end
@ -27,7 +26,6 @@ describe "class methods for classes with own write state" do
let(:klass) {Writer} let(:klass) {Writer}
it_should_behave_like "aasm model" it_should_behave_like "aasm model"
it "should include include all persistence mixins but write state" do it "should include include all persistence mixins but write state" do
klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
end end
end end
@ -36,7 +34,6 @@ describe "class methods for classes without persistence" do
let(:klass) {Transient} let(:klass) {Transient}
it_should_behave_like "aasm model" it_should_behave_like "aasm model"
it "should include all mixins but persistence" do it "should include all mixins but persistence" do
klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::WriteState)
klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) klass.included_modules.should_not be_include(AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence)
end end
end end