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

may configure to not allow direct assignment for persisted AASM models #53

This commit is contained in:
Thorsten Böttger 2014-05-18 14:21:35 +02:00
parent 887a1658da
commit 163859caef
7 changed files with 80 additions and 7 deletions

View file

@ -2,6 +2,7 @@
## 4.0.0 (not yet released)
* may configure to not allow direct assignment for persisted AASM models (see [issue #53](https://github.com/aasm/aasm/issues/53))
* **DSL change**: callbacks don't require `to_state` parameter anymore, but still support it
(closing issues
[#11](https://github.com/aasm/aasm/issues/11),

View file

@ -278,6 +278,34 @@ class Job < ActiveRecord::Base
end
```
If you want to make sure that the _AASM_ column for storing the state is not directly assigned,
configure _AASM_ to not allow direct assignment, like this:
```ruby
class Job < ActiveRecord::Base
include AASM
aasm :no_direct_assignment => true do
state :sleeping, :initial => true
state :running
event :run do
transitions :from => :sleeping, :to => :running
end
end
end
```
resulting in this:
```ruby
job = Job.create
job.aasm_state # => 'sleeping'
job.aasm_state = :running # => raises AASM::NoDirectAssignmentError
job.aasm_state # => 'sleeping'
```
### Sequel
AASM also supports [Sequel](http://sequel.jeremyevans.net/) besides _ActiveRecord_ and _Mongoid_.

View file

@ -4,7 +4,7 @@ module AASM
def initialize(clazz, options={}, &block)
@clazz = clazz
@state_machine = AASM::StateMachine[@clazz]
@state_machine.config.column = options[:column].to_sym if options[:column]
@state_machine.config.column ||= (options[:column] || :aasm_state).to_sym
@options = options
# let's cry if the transition is invalid
@ -13,11 +13,21 @@ module AASM
# create named scopes for each state
configure :create_scopes, true
# don't store any new state if the model is invalid
# don't store any new state if the model is invalid (in ActiveRecord)
configure :skip_validation_on_save, false
# use requires_new for nested transactions
# use requires_new for nested transactions (in ActiveRecord)
configure :requires_new_transaction, true
# set to true to forbid direct assignment of aasm_state column (in ActiveRecord)
configure :no_direct_assignment, false
if @state_machine.config.no_direct_assignment
@clazz.send(:define_method, "#{@state_machine.config.column}=") do |state_name|
raise AASM::NoDirectAssignmentError.new('direct assignment of AASM column has been disabled (see AASM configuration for this class)')
end
end
end
def initial_state(new_initial_state=nil)

View file

@ -1,4 +1,5 @@
module AASM
class InvalidTransition < RuntimeError; end
class UndefinedState < RuntimeError; end
class NoDirectAssignmentError < RuntimeError; end
end

View file

@ -1,5 +1,5 @@
ActiveRecord::Migration.suppress_messages do
%w{gates readers writers transients simples simple_new_dsls no_scopes thieves localizer_test_models persisted_states provided_and_persisted_states}.each do |table_name|
%w{gates readers writers transients simples simple_new_dsls no_scopes no_direct_assignments thieves localizer_test_models persisted_states provided_and_persisted_states}.each do |table_name|
ActiveRecord::Migration.create_table table_name, :force => true do |t|
t.string "aasm_state"
end

View file

@ -48,7 +48,22 @@ end
class NoScope < ActiveRecord::Base
include AASM
aasm :create_scopes => false do
state :ignored_scope
state :pending, :initial => true
state :running
event :run do
transitions :from => :pending, :to => :running
end
end
end
class NoDirectAssignment < ActiveRecord::Base
include AASM
aasm :no_direct_assignment => true do
state :pending, :initial => true
state :running
event :run do
transitions :from => :pending, :to => :running
end
end
end

View file

@ -93,10 +93,28 @@ describe "named scopes with the new DSL" do
end
it "does not create scopes if requested" do
expect(NoScope).not_to respond_to(:ignored_scope)
expect(NoScope).not_to respond_to(:pending)
end
end
end # scopes
describe "direct assignment" do
it "is allowed by default" do
obj = NoScope.create
expect(obj.aasm_state.to_sym).to eql :pending
obj.aasm_state = :running
expect(obj.aasm_state.to_sym).to eql :running
end
it "is forbidden if configured" do
obj = NoDirectAssignment.create
expect(obj.aasm_state.to_sym).to eql :pending
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
expect(obj.aasm_state.to_sym).to eql :pending
end
end # direct assignment
describe 'initial states' do