aasm 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.0.2
4
+
5
+ * ActiveRecord persistence can ignore validation when trying to save invalid models
6
+
3
7
  ## 3.0.1
4
8
 
5
9
  * added support for Mongoid (Thanks, Michał Taberski)
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2011 Scott Barron
1
+ Copyright (c) 2006-2012 Scott Barron
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,7 +2,10 @@
2
2
 
3
3
  This package contains AASM, a library for adding finite state machines to Ruby classes.
4
4
 
5
- AASM started as the acts_as_state_machine plugin but has evolved into a more generic library that no longer targets only ActiveRecord models.
5
+ AASM started as the acts_as_state_machine plugin but has evolved into a more generic library
6
+ that no longer targets only ActiveRecord models. It currently provides adapters for
7
+ [ActiveRecord](http://api.rubyonrails.org/classes/ActiveRecord/Base.html) and
8
+ [Mongoid](http://mongoid.org/).
6
9
 
7
10
  ## Features ##
8
11
 
@@ -54,7 +57,9 @@ gem 'aasm'
54
57
  % sudo gem install pkg/aasm-x.y.z.gem
55
58
  ```
56
59
 
57
- ## Simple Example ##
60
+ ## Examples ##
61
+
62
+ ### Simple Example ###
58
63
 
59
64
  Here's a quick example highlighting some of the features.
60
65
 
@@ -79,7 +84,7 @@ class Conversation
79
84
  end
80
85
  ```
81
86
 
82
- ## A Slightly More Complex Example ##
87
+ ### A Slightly More Complex Example ###
83
88
 
84
89
  This example uses a few of the more complex features available.
85
90
 
@@ -114,7 +119,7 @@ This example uses a few of the more complex features available.
114
119
  end
115
120
  ```
116
121
 
117
- ## Callbacks around events
122
+ ### Callbacks around events ###
118
123
  ```ruby
119
124
  class Relationship
120
125
  include AASM
@@ -132,6 +137,27 @@ This example uses a few of the more complex features available.
132
137
  end
133
138
  ```
134
139
 
140
+ ### Persistence example ###
141
+ ```ruby
142
+ class InvalidPersistor < ActiveRecord::Base
143
+ include AASM
144
+ aasm :column => :status, :skip_validation_on_save => true do
145
+ state :sleeping, :initial => true
146
+ state :running
147
+ event :run do
148
+ transitions :to => :running, :from => :sleeping
149
+ end
150
+ event :sleep do
151
+ transitions :to => :sleeping, :from => :running
152
+ end
153
+ end
154
+ validates_presence_of :name
155
+ end
156
+ ```
157
+ This model can change AASM states which are stored into the database, even if the model itself is invalid!
158
+
159
+
160
+
135
161
  ## Changelog ##
136
162
 
137
163
  Look at the [CHANGELOG](https://github.com/rubyist/aasm/blob/master/CHANGELOG.md) for details.
@@ -153,7 +179,7 @@ purpose.
153
179
 
154
180
  ## License ##
155
181
 
156
- Copyright (c) 2006-2011 Scott Barron
182
+ Copyright (c) 2006-2012 Scott Barron
157
183
 
158
184
  Permission is hereby granted, free of charge, to any person obtaining
159
185
  a copy of this software and associated documentation files (the
data/lib/aasm/base.rb CHANGED
@@ -4,11 +4,18 @@ module AASM
4
4
  @clazz = clazz
5
5
  sm = AASM::StateMachine[@clazz]
6
6
  sm.config.column = options[:column].to_sym if options[:column]
7
+
7
8
  if options.key?(:whiny_transitions)
8
9
  sm.config.whiny_transitions = options[:whiny_transitions]
9
10
  else
10
11
  sm.config.whiny_transitions = true # this is the default, so let's cry
11
12
  end
13
+
14
+ if options.key?(:skip_validation_on_save)
15
+ sm.config.skip_validation_on_save = options[:skip_validation_on_save]
16
+ else
17
+ sm.config.skip_validation_on_save = false # this is the default, so don't store any new state if the model is invalid
18
+ end
12
19
  end
13
20
 
14
21
  def state(name, options={})
@@ -196,7 +196,12 @@ module AASM
196
196
  old_value = read_attribute(self.class.aasm_column)
197
197
  write_attribute(self.class.aasm_column, state.to_s)
198
198
 
199
- unless self.save
199
+ success = if AASM::StateMachine[self.class].config.skip_validation_on_save && !self.valid?
200
+ self.class.update_all({ self.class.aasm_column => state.to_s }, self.class.primary_key => self.id) == 1
201
+ else
202
+ self.save
203
+ end
204
+ unless success
200
205
  write_attribute(self.class.aasm_column, old_value)
201
206
  return false
202
207
  end
data/lib/aasm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module AASM
2
- VERSION = "3.0.1"
2
+ VERSION = "3.0.2"
3
3
  end
@@ -0,0 +1,16 @@
1
+ require 'active_record'
2
+
3
+ class InvalidPersistor < ActiveRecord::Base
4
+ include AASM
5
+ aasm :column => :status, :skip_validation_on_save => true do
6
+ state :sleeping, :initial => true
7
+ state :running
8
+ event :run do
9
+ transitions :to => :running, :from => :sleeping
10
+ end
11
+ event :sleep do
12
+ transitions :to => :sleeping, :from => :running
13
+ end
14
+ end
15
+ validates_presence_of :name
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_record'
2
+
3
+ class Validator < ActiveRecord::Base
4
+ include AASM
5
+ aasm :column => :status do
6
+ state :sleeping, :initial => true
7
+ state :running
8
+ event :run do
9
+ transitions :to => :running, :from => :sleeping
10
+ end
11
+ event :sleep do
12
+ transitions :to => :sleeping, :from => :running
13
+ end
14
+ end
15
+ validates_presence_of :name
16
+ end
data/spec/schema.rb CHANGED
@@ -4,4 +4,14 @@ ActiveRecord::Schema.define(:version => 0) do
4
4
  create_table table_name, :force => true
5
5
  end
6
6
 
7
+ create_table "validators", :force => true do |t|
8
+ t.string "name"
9
+ t.string "status"
10
+ end
11
+
12
+ create_table "invalid_persistors", :force => true do |t|
13
+ t.string "name"
14
+ t.string "status"
15
+ end
16
+
7
17
  end
@@ -103,75 +103,16 @@ describe AASM, '- initial states' do
103
103
  end
104
104
  end
105
105
 
106
- describe AASM, '- event firing with persistence' do
107
- it 'should update the current state' do
108
- foo = Foo.new
109
- foo.close!
110
-
111
- foo.aasm_current_state.should == :closed
112
- end
113
-
106
+ describe AASM, 'success callbacks' do
114
107
  it 'should call the success callback if one was provided' do
115
108
  foo = Foo.new
116
-
117
109
  foo.should_receive(:success_callback)
118
-
119
110
  foo.close!
120
111
  end
121
112
 
122
- it 'should attempt to persist if aasm_write_state is defined' do
123
- foo = Foo.new
124
-
125
- def foo.aasm_write_state
126
- end
127
-
128
- foo.should_receive(:aasm_write_state)
129
-
130
- foo.close!
131
- end
132
-
133
- it 'should return true if aasm_write_state is defined and returns true' do
134
- foo = Foo.new
135
-
136
- def foo.aasm_write_state(state)
137
- true
138
- end
139
-
140
- foo.close!.should be_true
141
- end
142
-
143
- it 'should return false if aasm_write_state is defined and returns false' do
144
- foo = Foo.new
145
-
146
- def foo.aasm_write_state(state)
147
- false
148
- end
149
-
150
- foo.close!.should be_false
151
- end
152
-
153
- it "should not update the aasm_current_state if the write fails" do
154
- foo = Foo.new
155
-
156
- def foo.aasm_write_state
157
- false
158
- end
159
-
160
- foo.should_receive(:aasm_write_state)
161
-
162
- foo.close!
163
- foo.aasm_current_state.should == :open
164
- end
165
113
  end
166
114
 
167
115
  describe AASM, '- event firing without persistence' do
168
- it 'should update the current state' do
169
- foo = Foo.new
170
- foo.close
171
-
172
- foo.aasm_current_state.should == :closed
173
- end
174
-
175
116
  it 'should attempt to persist if aasm_write_state is defined' do
176
117
  foo = Foo.new
177
118
 
@@ -184,18 +125,6 @@ describe AASM, '- event firing without persistence' do
184
125
  end
185
126
  end
186
127
 
187
- describe AASM, '- persistence' do
188
- it 'should read the state if it has not been set and aasm_read_state is defined' do
189
- foo = Foo.new
190
- def foo.aasm_read_state
191
- end
192
-
193
- foo.should_receive(:aasm_read_state)
194
-
195
- foo.aasm_current_state
196
- end
197
- end
198
-
199
128
  describe AASM, '- getting events for a state' do
200
129
  it '#aasm_events_for_current_state should use current state' do
201
130
  foo = Foo.new
@@ -246,3 +246,52 @@ describe 'Thieves' do
246
246
  Thief.new(:skilled => false).aasm_current_state.should == :jailed
247
247
  end
248
248
  end
249
+
250
+ describe 'transitions with persistence' do
251
+
252
+ it 'should not store states for invalid models' do
253
+ validator = Validator.create(:name => 'name')
254
+ validator.should be_valid
255
+ validator.should be_sleeping
256
+
257
+ validator.name = nil
258
+ validator.should_not be_valid
259
+ validator.run!.should be_false
260
+ validator.should be_sleeping
261
+
262
+ validator.reload
263
+ validator.should_not be_running
264
+ validator.should be_sleeping
265
+
266
+ validator.name = 'another name'
267
+ validator.should be_valid
268
+ validator.run!.should be_true
269
+ validator.should be_running
270
+
271
+ validator.reload
272
+ validator.should be_running
273
+ validator.should_not be_sleeping
274
+ end
275
+
276
+ it 'should store states for invalid models if configured' do
277
+ persistor = InvalidPersistor.create(:name => 'name')
278
+ persistor.should be_valid
279
+ persistor.should be_sleeping
280
+
281
+ persistor.name = nil
282
+ persistor.should_not be_valid
283
+ persistor.run!.should be_true
284
+ persistor.should be_running
285
+
286
+ persistor = InvalidPersistor.find(persistor.id)
287
+ persistor.valid?
288
+ persistor.should be_valid
289
+ persistor.should be_running
290
+ persistor.should_not be_sleeping
291
+
292
+ persistor.reload
293
+ persistor.should be_running
294
+ persistor.should_not be_sleeping
295
+ end
296
+
297
+ end
@@ -22,16 +22,19 @@ describe AASM::SupportingClasses::Localizer do
22
22
  before(:all) do
23
23
  I18n.load_path << 'spec/en.yml'
24
24
  I18n.default_locale = :en
25
+ I18n.reload!
25
26
  end
26
27
 
27
- after(:all) { I18n.load_path.clear }
28
+ after(:all) do
29
+ I18n.load_path.clear
30
+ end
28
31
 
29
32
  let (:foo_opened) { LocalizerTestModel.new }
30
33
  let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
31
34
 
32
35
  context 'aasm_human_state' do
33
36
  it 'should return translated state value' do
34
- foo_opened.aasm_human_state.should == "It's opened now!"
37
+ foo_opened.aasm_human_state.should == "It's opened now!"
35
38
  end
36
39
 
37
40
  it 'should return humanized value if not localized' do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aasm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 1
10
- version: 3.0.1
9
+ - 2
10
+ version: 3.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Scott Barron
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-12-21 00:00:00 +01:00
21
+ date: 2012-01-16 00:00:00 +01:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -182,9 +182,11 @@ files:
182
182
  - spec/database.yml
183
183
  - spec/en.yml
184
184
  - spec/models/conversation.rb
185
+ - spec/models/invalid_persistor.rb
185
186
  - spec/models/not_auto_loaded/process.rb
186
187
  - spec/models/process_with_new_dsl.rb
187
188
  - spec/models/silencer.rb
189
+ - spec/models/validator.rb
188
190
  - spec/schema.rb
189
191
  - spec/spec_helper.rb
190
192
  - spec/spec_helpers/models_spec_helper.rb
@@ -237,9 +239,11 @@ test_files:
237
239
  - spec/database.yml
238
240
  - spec/en.yml
239
241
  - spec/models/conversation.rb
242
+ - spec/models/invalid_persistor.rb
240
243
  - spec/models/not_auto_loaded/process.rb
241
244
  - spec/models/process_with_new_dsl.rb
242
245
  - spec/models/silencer.rb
246
+ - spec/models/validator.rb
243
247
  - spec/schema.rb
244
248
  - spec/spec_helper.rb
245
249
  - spec/spec_helpers/models_spec_helper.rb