Skip to content

Commit

Permalink
no need for WriteState mixin anymore (to keep adding persistence simple)
Browse files Browse the repository at this point in the history
  • Loading branch information
alto committed Apr 24, 2013
1 parent 52181d8 commit 95ef7fc
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 70 deletions.
10 changes: 10 additions & 0 deletions API
Expand Up @@ -7,3 +7,13 @@ Overwrite method to read the current state
# retrieve the current state manually
end
end

Overwrite method to write the current state

class MyClass
include AASM

def aasm_write_state
# store the current state manually
end
end
5 changes: 5 additions & 0 deletions lib/aasm/aasm.rb
Expand Up @@ -86,6 +86,11 @@ def aasm_read_state
aasm.enter_initial_state
end

# may be overwritten by persistence mixins
def aasm_write_state(new_state)
true
end

# deprecated
def aasm_current_state
# warn "#aasm_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.state instead!"
Expand Down
5 changes: 1 addition & 4 deletions lib/aasm/instance_base.rb
Expand Up @@ -69,10 +69,7 @@ def may_fire_event?(name, *args)
end

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)
end
save_success = @instance.aasm_write_state(state)
self.current_state = state if save_success
save_success
end
Expand Down
61 changes: 28 additions & 33 deletions lib/aasm/persistence/active_record_persistence.rb
Expand Up @@ -7,7 +7,6 @@ module ActiveRecordPersistence
# * includes InstanceMethods
#
# Unless the corresponding methods are already defined, it includes
# * WriteState
# * WriteStateWithoutPersistence
#
# Adds
Expand All @@ -34,7 +33,6 @@ def self.included(base)
base.send(:include, AASM::Persistence::Base)
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
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)

if ActiveRecord::VERSION::MAJOR >= 3
Expand Down Expand Up @@ -74,7 +72,33 @@ def with_state_scope(state)

module InstanceMethods

private
# 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

# Ensures that if the aasm_state column is nil and the record is new
# that the initial state gets populated before validation on create
Expand All @@ -100,8 +124,7 @@ def aasm_fire_event(name, options, *args)
super
end
end

end
end # InstanceMethods

module WriteStateWithoutPersistence
# Writes <tt>state</tt> to the state column, but does not persist it to the database
Expand All @@ -121,34 +144,6 @@ def aasm_write_state_without_persistence(state)
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
53 changes: 24 additions & 29 deletions lib/aasm/persistence/mongoid_persistence.rb
Expand Up @@ -7,7 +7,6 @@ module MongoidPersistence
# * includes InstanceMethods
#
# Unless the corresponding methods are already defined, it includes
# * WriteState
# * WriteStateWithoutPersistence
#
# Adds
Expand Down Expand Up @@ -36,7 +35,6 @@ def self.included(base)
base.send(:include, AASM::Persistence::Base)
base.extend AASM::Persistence::MongoidPersistence::ClassMethods
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)

# Mongoid's Validatable gem dependency goes not have a before_validation_on_xxx hook yet.
Expand Down Expand Up @@ -68,7 +66,29 @@ def with_state_scope(state)

module InstanceMethods

private
# 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
def aasm_write_state(state)
old_value = read_attribute(self.class.aasm_column)
write_attribute(self.class.aasm_column, state.to_s)

unless self.save(:validate => false)
write_attribute(self.class.aasm_column, old_value)
return false
end

true
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
Expand All @@ -88,8 +108,7 @@ module InstanceMethods
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
end # InstanceMethods

module WriteStateWithoutPersistence
# Writes <tt>state</tt> to the state column, but does not persist it to the database
Expand All @@ -109,30 +128,6 @@ def aasm_write_state_without_persistence(state)
end
end

module WriteState
# 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
def aasm_write_state(state)
old_value = read_attribute(self.class.aasm_column)
write_attribute(self.class.aasm_column, state.to_s)

unless self.save(:validate => false)
write_attribute(self.class.aasm_column, old_value)
return false
end

true
end
end

module NamedScopeMethods
def aasm_state_with_named_scope name, options = {}
aasm_state_without_named_scope name, options
Expand Down
24 changes: 24 additions & 0 deletions spec/models/active_record/api.rb
@@ -1,43 +1,67 @@
class DefaultState
attr_accessor :transient_store
include AASM
aasm do
state :alpha, :initial => true
state :beta
state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end
end

class ProvidedState
attr_accessor :transient_store
include AASM
aasm do
state :alpha, :initial => true
state :beta
state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end

def aasm_read_state
:beta
end

def aasm_write_state(new_state)
@transient_store = new_state
end
end

class PersistedState < ActiveRecord::Base
attr_accessor :transient_store
include AASM
aasm do
state :alpha, :initial => true
state :beta
state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end
end

class ProvidedAndPersistedState < ActiveRecord::Base
attr_accessor :transient_store
include AASM
aasm do
state :alpha, :initial => true
state :beta
state :gamma
event :release do
transitions :from => [:alpha, :beta, :gamma], :to => :beta
end
end

def aasm_read_state
:gamma
end

def aasm_write_state(new_state)
@transient_store = new_state
end
end
28 changes: 27 additions & 1 deletion spec/unit/api_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'models/active_record/api.rb'

describe "retrieving the current state" do
describe "reading the current state" do
it "uses the AASM default" do
DefaultState.new.aasm.current_state.should eql :alpha
end
Expand All @@ -18,3 +18,29 @@
ProvidedAndPersistedState.new.aasm.current_state.should eql :gamma
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
3 changes: 0 additions & 3 deletions spec/unit/persistence/active_record_persistence_spec.rb
Expand Up @@ -18,7 +18,6 @@
let(:klass) {Gate}
it_should_behave_like "aasm model"
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)
end
end
Expand All @@ -27,7 +26,6 @@
let(:klass) {Writer}
it_should_behave_like "aasm model"
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)
end
end
Expand All @@ -36,7 +34,6 @@
let(:klass) {Transient}
it_should_behave_like "aasm model"
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)
end
end
Expand Down

0 comments on commit 95ef7fc

Please sign in to comment.