aasm 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
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