mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
ActiveRecord persistence can ignore validation when trying to save invalid models
This commit is contained in:
parent
c12be51c9c
commit
921cfdad5c
8 changed files with 110 additions and 28 deletions
|
@ -1,5 +1,9 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 3.0.x
|
||||
|
||||
* ActiveRecord persistence can ignore validation when trying to save invalid models
|
||||
|
||||
## 3.0.1
|
||||
|
||||
* added support for Mongoid (Thanks, Michał Taberski)
|
||||
|
|
29
README.md
29
README.md
|
@ -57,7 +57,9 @@ gem 'aasm'
|
|||
% sudo gem install pkg/aasm-x.y.z.gem
|
||||
```
|
||||
|
||||
## Simple Example ##
|
||||
## Examples ##
|
||||
|
||||
### Simple Example ###
|
||||
|
||||
Here's a quick example highlighting some of the features.
|
||||
|
||||
|
@ -82,7 +84,7 @@ class Conversation
|
|||
end
|
||||
```
|
||||
|
||||
## A Slightly More Complex Example ##
|
||||
### A Slightly More Complex Example ###
|
||||
|
||||
This example uses a few of the more complex features available.
|
||||
|
||||
|
@ -117,7 +119,7 @@ This example uses a few of the more complex features available.
|
|||
end
|
||||
```
|
||||
|
||||
## Callbacks around events
|
||||
### Callbacks around events ###
|
||||
```ruby
|
||||
class Relationship
|
||||
include AASM
|
||||
|
@ -135,6 +137,27 @@ This example uses a few of the more complex features available.
|
|||
end
|
||||
```
|
||||
|
||||
### Persistence example ###
|
||||
```ruby
|
||||
class InvalidPersistor < ActiveRecord::Base
|
||||
include AASM
|
||||
aasm :column => :status, :skip_validation_on_save => true do
|
||||
state :sleeping, :initial => true
|
||||
state :running
|
||||
event :run do
|
||||
transitions :to => :running, :from => :sleeping
|
||||
end
|
||||
event :sleep do
|
||||
transitions :to => :sleeping, :from => :running
|
||||
end
|
||||
end
|
||||
validates_presence_of :name
|
||||
end
|
||||
```
|
||||
This model can change AASM states which are stored into the database, even if the model itself is invalid!
|
||||
|
||||
|
||||
|
||||
## Changelog ##
|
||||
|
||||
Look at the [CHANGELOG](https://github.com/rubyist/aasm/blob/master/CHANGELOG.md) for details.
|
||||
|
|
|
@ -4,11 +4,18 @@ module AASM
|
|||
@clazz = clazz
|
||||
sm = AASM::StateMachine[@clazz]
|
||||
sm.config.column = options[:column].to_sym if options[:column]
|
||||
|
||||
if options.key?(:whiny_transitions)
|
||||
sm.config.whiny_transitions = options[:whiny_transitions]
|
||||
else
|
||||
sm.config.whiny_transitions = true # this is the default, so let's cry
|
||||
end
|
||||
|
||||
if options.key?(:skip_validation_on_save)
|
||||
sm.config.skip_validation_on_save = options[:skip_validation_on_save]
|
||||
else
|
||||
sm.config.skip_validation_on_save = false # this is the default, so don't store any new state if the model is invalid
|
||||
end
|
||||
end
|
||||
|
||||
def state(name, options={})
|
||||
|
|
|
@ -196,7 +196,12 @@ module AASM
|
|||
old_value = read_attribute(self.class.aasm_column)
|
||||
write_attribute(self.class.aasm_column, state.to_s)
|
||||
|
||||
unless self.save
|
||||
success = if AASM::StateMachine[self.class].config.skip_validation_on_save && !self.valid?
|
||||
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
|
||||
|
|
16
spec/models/invalid_persistor.rb
Normal file
16
spec/models/invalid_persistor.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'active_record'
|
||||
|
||||
class InvalidPersistor < ActiveRecord::Base
|
||||
include AASM
|
||||
aasm :column => :status, :skip_validation_on_save => true do
|
||||
state :sleeping, :initial => true
|
||||
state :running
|
||||
event :run do
|
||||
transitions :to => :running, :from => :sleeping
|
||||
end
|
||||
event :sleep do
|
||||
transitions :to => :sleeping, :from => :running
|
||||
end
|
||||
end
|
||||
validates_presence_of :name
|
||||
end
|
16
spec/models/validator.rb
Normal file
16
spec/models/validator.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'active_record'
|
||||
|
||||
class Validator < ActiveRecord::Base
|
||||
include AASM
|
||||
aasm :column => :status do
|
||||
state :sleeping, :initial => true
|
||||
state :running
|
||||
event :run do
|
||||
transitions :to => :running, :from => :sleeping
|
||||
end
|
||||
event :sleep do
|
||||
transitions :to => :sleeping, :from => :running
|
||||
end
|
||||
end
|
||||
validates_presence_of :name
|
||||
end
|
|
@ -9,4 +9,9 @@ ActiveRecord::Schema.define(:version => 0) do
|
|||
t.string "status"
|
||||
end
|
||||
|
||||
create_table "invalid_persistors", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "status"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -68,21 +68,6 @@ class Thief < ActiveRecord::Base
|
|||
attr_accessor :skilled, :aasm_state
|
||||
end
|
||||
|
||||
class Validator < ActiveRecord::Base
|
||||
include AASM
|
||||
aasm :column => :status do
|
||||
state :sleeping, :initial => true
|
||||
state :running
|
||||
event :run do
|
||||
transitions :to => :running, :from => :sleeping
|
||||
end
|
||||
event :sleep do
|
||||
transitions :to => :sleeping, :from => :running
|
||||
end
|
||||
end
|
||||
validates_presence_of :name
|
||||
end
|
||||
|
||||
shared_examples_for "aasm model" do
|
||||
it "should include AASM::Persistence::ActiveRecordPersistence" do
|
||||
@klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence)
|
||||
|
@ -264,19 +249,19 @@ end
|
|||
|
||||
describe 'transitions with persistence' do
|
||||
|
||||
it 'should succeed and store the new state' do
|
||||
it 'should not store states for invalid models' do
|
||||
validator = Validator.create(:name => 'name')
|
||||
validator.should be_valid
|
||||
validator.should be_sleeping
|
||||
|
||||
# validator.name = nil
|
||||
# validator.should_not be_valid
|
||||
# validator.run!.should be_false
|
||||
# validator.should be_running
|
||||
#
|
||||
# validator.reload
|
||||
# validator.should_not be_running
|
||||
# validator.should be_sleeping
|
||||
validator.name = nil
|
||||
validator.should_not be_valid
|
||||
validator.run!.should be_false
|
||||
validator.should be_sleeping
|
||||
|
||||
validator.reload
|
||||
validator.should_not be_running
|
||||
validator.should be_sleeping
|
||||
|
||||
validator.name = 'another name'
|
||||
validator.should be_valid
|
||||
|
@ -288,4 +273,25 @@ describe 'transitions with persistence' do
|
|||
validator.should_not be_sleeping
|
||||
end
|
||||
|
||||
it 'should store states for invalid models if configured' do
|
||||
persistor = InvalidPersistor.create(:name => 'name')
|
||||
persistor.should be_valid
|
||||
persistor.should be_sleeping
|
||||
|
||||
persistor.name = nil
|
||||
persistor.should_not be_valid
|
||||
persistor.run!.should be_true
|
||||
persistor.should be_running
|
||||
|
||||
persistor = InvalidPersistor.find(persistor.id)
|
||||
persistor.valid?
|
||||
persistor.should be_valid
|
||||
persistor.should be_running
|
||||
persistor.should_not be_sleeping
|
||||
|
||||
persistor.reload
|
||||
persistor.should be_running
|
||||
persistor.should_not be_sleeping
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue