state_machine 0.9.4 → 0.10.0
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.rdoc +20 -0
- data/LICENSE +1 -1
- data/README.rdoc +74 -4
- data/Rakefile +3 -3
- data/lib/state_machine.rb +51 -24
- data/lib/state_machine/{guard.rb → branch.rb} +34 -40
- data/lib/state_machine/callback.rb +13 -18
- data/lib/state_machine/error.rb +13 -0
- data/lib/state_machine/eval_helpers.rb +3 -0
- data/lib/state_machine/event.rb +67 -30
- data/lib/state_machine/event_collection.rb +20 -3
- data/lib/state_machine/extensions.rb +3 -3
- data/lib/state_machine/integrations.rb +7 -0
- data/lib/state_machine/integrations/active_model.rb +149 -59
- data/lib/state_machine/integrations/active_model/versions.rb +30 -0
- data/lib/state_machine/integrations/active_record.rb +74 -148
- data/lib/state_machine/integrations/active_record/locale.rb +0 -7
- data/lib/state_machine/integrations/active_record/versions.rb +149 -0
- data/lib/state_machine/integrations/base.rb +64 -0
- data/lib/state_machine/integrations/data_mapper.rb +50 -39
- data/lib/state_machine/integrations/data_mapper/observer.rb +47 -12
- data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
- data/lib/state_machine/integrations/mongo_mapper.rb +37 -64
- data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
- data/lib/state_machine/integrations/mongo_mapper/versions.rb +102 -0
- data/lib/state_machine/integrations/mongoid.rb +297 -0
- data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
- data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
- data/lib/state_machine/integrations/sequel.rb +99 -55
- data/lib/state_machine/integrations/sequel/versions.rb +40 -0
- data/lib/state_machine/machine.rb +273 -136
- data/lib/state_machine/machine_collection.rb +21 -13
- data/lib/state_machine/node_collection.rb +6 -1
- data/lib/state_machine/path.rb +120 -0
- data/lib/state_machine/path_collection.rb +90 -0
- data/lib/state_machine/state.rb +28 -9
- data/lib/state_machine/state_collection.rb +1 -1
- data/lib/state_machine/transition.rb +65 -6
- data/lib/state_machine/transition_collection.rb +1 -1
- data/test/files/en.yml +8 -0
- data/test/functional/state_machine_test.rb +15 -2
- data/test/unit/branch_test.rb +890 -0
- data/test/unit/callback_test.rb +9 -36
- data/test/unit/error_test.rb +43 -0
- data/test/unit/event_collection_test.rb +67 -33
- data/test/unit/event_test.rb +165 -38
- data/test/unit/integrations/active_model_test.rb +103 -3
- data/test/unit/integrations/active_record_test.rb +90 -43
- data/test/unit/integrations/base_test.rb +87 -0
- data/test/unit/integrations/data_mapper_test.rb +105 -44
- data/test/unit/integrations/mongo_mapper_test.rb +261 -64
- data/test/unit/integrations/mongoid_test.rb +1529 -0
- data/test/unit/integrations/sequel_test.rb +33 -49
- data/test/unit/integrations_test.rb +4 -0
- data/test/unit/invalid_event_test.rb +15 -2
- data/test/unit/invalid_parallel_transition_test.rb +18 -0
- data/test/unit/invalid_transition_test.rb +72 -2
- data/test/unit/machine_collection_test.rb +55 -61
- data/test/unit/machine_test.rb +388 -26
- data/test/unit/node_collection_test.rb +14 -4
- data/test/unit/path_collection_test.rb +266 -0
- data/test/unit/path_test.rb +485 -0
- data/test/unit/state_collection_test.rb +30 -0
- data/test/unit/state_test.rb +82 -35
- data/test/unit/transition_collection_test.rb +48 -44
- data/test/unit/transition_test.rb +198 -41
- metadata +111 -74
- data/test/unit/guard_test.rb +0 -909
@@ -0,0 +1,30 @@
|
|
1
|
+
module StateMachine
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module ActiveModel
|
4
|
+
version '2.x' do
|
5
|
+
def self.active?
|
6
|
+
!defined?(::ActiveModel::VERSION) || ::ActiveModel::VERSION::MAJOR == 2
|
7
|
+
end
|
8
|
+
|
9
|
+
def define_validation_hook
|
10
|
+
action = self.action
|
11
|
+
define_helper(:instance, :valid?) do |machine, object, _super, *|
|
12
|
+
object.class.state_machines.transitions(object, action, :after => false).perform { _super.call }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
version '3.0.x' do
|
18
|
+
def self.active?
|
19
|
+
defined?(::ActiveModel::VERSION) && ::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR == 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_validation_hook
|
23
|
+
# +around+ callbacks don't have direct access to results until AS 3.1
|
24
|
+
owner_class.set_callback(:validation, :after, 'value', :prepend => true)
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'state_machine/integrations/active_model'
|
2
|
+
|
1
3
|
module StateMachine
|
2
4
|
module Integrations #:nodoc:
|
3
5
|
# Adds support for integrating state machines with ActiveRecord models.
|
@@ -219,15 +221,15 @@ module StateMachine
|
|
219
221
|
# *are* supported. For example, if a transition for a record's +state+
|
220
222
|
# attribute changes the state from +parked+ to +idling+ via the +ignite+
|
221
223
|
# event, the following observer methods are supported:
|
222
|
-
# * before/
|
223
|
-
# * before/
|
224
|
-
# * before/
|
225
|
-
# * before/
|
226
|
-
# * before/
|
227
|
-
# * before/
|
228
|
-
# * before/
|
229
|
-
# * before/
|
230
|
-
# * before/
|
224
|
+
# * before/after/after_failure_to-_ignite_from_parked_to_idling
|
225
|
+
# * before/after/after_failure_to-_ignite_from_parked
|
226
|
+
# * before/after/after_failure_to-_ignite_to_idling
|
227
|
+
# * before/after/after_failure_to-_ignite
|
228
|
+
# * before/after/after_failure_to-_transition_state_from_parked_to_idling
|
229
|
+
# * before/after/after_failure_to-_transition_state_from_parked
|
230
|
+
# * before/after/after_failure_to-_transition_state_to_idling
|
231
|
+
# * before/after/after_failure_to-_transition_state
|
232
|
+
# * before/after/after_failure_to-_transition
|
231
233
|
#
|
232
234
|
# The following class shows an example of some of these hooks:
|
233
235
|
#
|
@@ -313,8 +315,11 @@ module StateMachine
|
|
313
315
|
# events:
|
314
316
|
# park: 'estacionarse'
|
315
317
|
module ActiveRecord
|
318
|
+
include Base
|
316
319
|
include ActiveModel
|
317
320
|
|
321
|
+
require 'state_machine/integrations/active_record/versions'
|
322
|
+
|
318
323
|
# The default options to use for state machines using this integration
|
319
324
|
@defaults = {:action => :save}
|
320
325
|
|
@@ -327,83 +332,50 @@ module StateMachine
|
|
327
332
|
|
328
333
|
def self.extended(base) #:nodoc:
|
329
334
|
require 'active_record/version'
|
330
|
-
|
331
|
-
|
332
|
-
::ActiveRecord::Observer.class_eval do
|
333
|
-
include StateMachine::Integrations::ActiveModel::Observer
|
334
|
-
end unless ::ActiveRecord::Observer < StateMachine::Integrations::ActiveModel::Observer
|
335
|
-
|
336
|
-
if defined?(I18n)
|
337
|
-
locale = "#{File.dirname(__FILE__)}/active_record/locale.rb"
|
338
|
-
I18n.load_path.unshift(locale) unless I18n.load_path.include?(locale)
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
# Adds a validation error to the given object
|
343
|
-
def invalidate(object, attribute, message, values = [])
|
344
|
-
if defined?(I18n)
|
345
|
-
super
|
346
|
-
else
|
347
|
-
object.errors.add(self.attribute(attribute), generate_message(message, values))
|
348
|
-
end
|
335
|
+
super
|
349
336
|
end
|
350
337
|
|
351
338
|
protected
|
352
|
-
#
|
353
|
-
def
|
354
|
-
|
355
|
-
end
|
356
|
-
|
357
|
-
# Always adds validation support
|
358
|
-
def supports_validations?
|
359
|
-
true
|
339
|
+
# The name of this integration
|
340
|
+
def integration
|
341
|
+
:active_record
|
360
342
|
end
|
361
343
|
|
362
|
-
#
|
363
|
-
def
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
# Only adds dirty tracking support if ActiveRecord supports it
|
368
|
-
def supports_dirty_tracking?(object)
|
369
|
-
defined?(::ActiveRecord::Dirty) && object.respond_to?("#{attribute}_changed?") || super
|
344
|
+
# Loads locale files needed for translations
|
345
|
+
def load_locale
|
346
|
+
load_i18n_version
|
347
|
+
super
|
370
348
|
end
|
371
349
|
|
372
|
-
#
|
373
|
-
|
374
|
-
|
350
|
+
# Loads the version of the i18n library so that that proper
|
351
|
+
# interpolation syntax can be used
|
352
|
+
def load_i18n_version
|
353
|
+
begin
|
354
|
+
require 'i18n/version'
|
355
|
+
rescue Exception => ex
|
356
|
+
end
|
375
357
|
end
|
376
358
|
|
377
|
-
#
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
{:default => @messages[message]}
|
384
|
-
end
|
359
|
+
# Loads extensions to ActiveRecord's Observers
|
360
|
+
def load_observer_extensions
|
361
|
+
super
|
362
|
+
::ActiveRecord::Observer.class_eval do
|
363
|
+
include StateMachine::Integrations::ActiveModel::Observer
|
364
|
+
end unless ::ActiveRecord::Observer < StateMachine::Integrations::ActiveModel::Observer
|
385
365
|
end
|
386
366
|
|
387
|
-
# Only
|
388
|
-
def
|
389
|
-
|
390
|
-
super
|
391
|
-
else
|
392
|
-
value ? value.to_s.humanize.downcase : 'nil'
|
393
|
-
end
|
367
|
+
# Only runs validations on the action if using <tt>:save</tt>
|
368
|
+
def runs_validations_on_action?
|
369
|
+
action == :save
|
394
370
|
end
|
395
371
|
|
396
|
-
#
|
397
|
-
#
|
398
|
-
#
|
399
|
-
|
400
|
-
|
401
|
-
|
372
|
+
# Only allows state initialization on new records that aren't being
|
373
|
+
# created with a set of attributes that includes this machine's
|
374
|
+
# attribute.
|
375
|
+
def initialize_state?(object, options)
|
376
|
+
if object.new_record? && !object.instance_variable_defined?('@initialized_state_machines')
|
377
|
+
object.instance_variable_set('@initialized_state_machines', true)
|
402
378
|
super
|
403
|
-
elsif ::ActiveRecord::VERSION::MINOR == 3 && ::ActiveRecord::VERSION::TINY >= 2
|
404
|
-
klass.self_and_descendants_from_active_record
|
405
|
-
else
|
406
|
-
klass.self_and_descendents_from_active_record
|
407
379
|
end
|
408
380
|
end
|
409
381
|
|
@@ -411,66 +383,37 @@ module StateMachine
|
|
411
383
|
# initial state of the machine *before* any attributes are set on the
|
412
384
|
# object
|
413
385
|
def define_state_initializer
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
if new_record? && !@initialized_state_machines
|
426
|
-
@initialized_state_machines = true
|
427
|
-
|
428
|
-
ignore = if new_attributes
|
429
|
-
attributes = new_attributes.dup
|
430
|
-
attributes.stringify_keys!
|
431
|
-
if ::ActiveRecord::VERSION::MAJOR >= 3
|
432
|
-
sanitize_for_mass_assignment(attributes).keys
|
433
|
-
else
|
434
|
-
remove_attributes_protected_from_mass_assignment(attributes).keys
|
435
|
-
end
|
436
|
-
else
|
437
|
-
[]
|
438
|
-
end
|
439
|
-
|
440
|
-
initialize_state_machines(:dynamic => false, :ignore => ignore)
|
441
|
-
super
|
442
|
-
initialize_state_machines(:dynamic => true, :ignore => ignore)
|
443
|
-
else
|
444
|
-
super
|
445
|
-
end
|
446
|
-
end
|
447
|
-
end_eval
|
386
|
+
# Ensure that the attributes setter gets used to force initialization
|
387
|
+
# of the state machines
|
388
|
+
define_helper(:instance, :initialize) do |machine, object, _super, *args|
|
389
|
+
_super.call(args.shift || {}, *args)
|
390
|
+
end
|
391
|
+
|
392
|
+
# Hooks in to attribute initialization to set the states *prior*
|
393
|
+
# to the attributes being set
|
394
|
+
define_helper(:instance, :attributes=) do |machine, object, _super, new_attributes, *|
|
395
|
+
object.class.state_machines.initialize_states(object, :attributes => new_attributes) { _super.call }
|
396
|
+
end
|
448
397
|
end
|
449
398
|
|
450
|
-
#
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
# Still use class_eval here instance of define_instance_method since
|
457
|
-
# we need to be able to call +super+
|
458
|
-
@instance_helper_module.class_eval do
|
459
|
-
define_method("#{name}?") do |*args|
|
460
|
-
args.empty? ? super(*args) : self.class.state_machine(name).states.matches?(self, *args)
|
461
|
-
end
|
399
|
+
# Uses around callbacks to run state events if using the :save hook
|
400
|
+
def define_action_hook
|
401
|
+
if action_hook == :save
|
402
|
+
owner_class.set_callback(:save, :around, self, :prepend => true)
|
403
|
+
else
|
404
|
+
super
|
462
405
|
end
|
463
406
|
end
|
464
407
|
|
465
|
-
#
|
466
|
-
def
|
467
|
-
|
408
|
+
# Runs state events around the machine's :save action
|
409
|
+
def around_save(object)
|
410
|
+
object.class.state_machines.transitions(object, action).perform { yield }
|
468
411
|
end
|
469
412
|
|
470
413
|
# Creates a scope for finding records *with* a particular state or
|
471
414
|
# states for the attribute
|
472
415
|
def create_with_scope(name)
|
473
|
-
define_scope(name, lambda {|values| {
|
416
|
+
define_scope(name, lambda {|values| {attribute => values}})
|
474
417
|
end
|
475
418
|
|
476
419
|
# Creates a scope for finding records *without* a particular state or
|
@@ -478,7 +421,7 @@ module StateMachine
|
|
478
421
|
def create_without_scope(name)
|
479
422
|
define_scope(name, lambda {|values|
|
480
423
|
connection = owner_class.connection
|
481
|
-
|
424
|
+
["#{connection.quote_table_name(owner_class.table_name)}.#{connection.quote_column_name(attribute)} NOT IN (?)", values]
|
482
425
|
})
|
483
426
|
end
|
484
427
|
|
@@ -489,33 +432,16 @@ module StateMachine
|
|
489
432
|
object.class.transaction {raise ::ActiveRecord::Rollback unless yield}
|
490
433
|
end
|
491
434
|
|
492
|
-
private
|
493
435
|
# Defines a new named scope with the given name
|
494
436
|
def define_scope(name, scope)
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
# being used within the evaluation of a dynamic named scope, the
|
504
|
-
# scope must be generated manually. It's necessary to have access
|
505
|
-
# to the model so that the state names can be translated to their
|
506
|
-
# associated values and so that inheritance is respected properly.
|
507
|
-
owner_class.named_scope(name)
|
508
|
-
owner_class.scopes[name] = lambda do |model, *states|
|
509
|
-
machine_states = model.state_machine(machine_name).states
|
510
|
-
values = states.flatten.map {|state| machine_states.fetch(state).value}
|
511
|
-
|
512
|
-
::ActiveRecord::NamedScope::Scope.new(model, scope.call(values))
|
513
|
-
end
|
514
|
-
end
|
515
|
-
|
516
|
-
# Prevent the Machine class from wrapping the scope
|
517
|
-
false
|
518
|
-
end
|
437
|
+
lambda {|model, values| model.where(scope.call(values))}
|
438
|
+
end
|
439
|
+
|
440
|
+
# ActiveModel's use of method_missing / respond_to for attribute methods
|
441
|
+
# breaks both ancestor lookups and defined?(super). Need to special-case
|
442
|
+
# the existence of query attribute methods.
|
443
|
+
def owner_class_ancestor_has_method?(method)
|
444
|
+
method == "#{name}?" || super
|
519
445
|
end
|
520
446
|
end
|
521
447
|
end
|
@@ -2,13 +2,6 @@ filename = "#{File.dirname(__FILE__)}/../active_model/locale.rb"
|
|
2
2
|
translations = eval(IO.read(filename), binding, filename)
|
3
3
|
translations[:en][:activerecord] = translations[:en].delete(:activemodel)
|
4
4
|
|
5
|
-
# Only ActiveRecord 2.3.5+ can pull i18n >= 0.1.3 from system-wide gems (and
|
6
|
-
# therefore possibly have I18n::VERSION available)
|
7
|
-
begin
|
8
|
-
require 'i18n/version'
|
9
|
-
rescue Exception => ex
|
10
|
-
end unless ::ActiveRecord::VERSION::MAJOR == 2 && (::ActiveRecord::VERSION::MINOR < 3 || ::ActiveRecord::VERSION::TINY < 5)
|
11
|
-
|
12
5
|
# Only i18n 0.4.0+ has the new %{key} syntax
|
13
6
|
if !defined?(I18n::VERSION) || I18n::VERSION < '0.4.0'
|
14
7
|
translations[:en][:activerecord][:errors][:messages].each do |key, message|
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module StateMachine
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module ActiveRecord
|
4
|
+
version '2.x' do
|
5
|
+
def self.active?
|
6
|
+
::ActiveRecord::VERSION::MAJOR == 2
|
7
|
+
end
|
8
|
+
|
9
|
+
def load_locale
|
10
|
+
super if defined?(I18n)
|
11
|
+
end
|
12
|
+
|
13
|
+
def define_scope(name, scope)
|
14
|
+
if owner_class.respond_to?(:named_scope)
|
15
|
+
name = name.to_sym
|
16
|
+
machine_name = self.name
|
17
|
+
|
18
|
+
# Since ActiveRecord does not allow direct access to the model
|
19
|
+
# being used within the evaluation of a dynamic named scope, the
|
20
|
+
# scope must be generated manually. It's necessary to have access
|
21
|
+
# to the model so that the state names can be translated to their
|
22
|
+
# associated values and so that inheritance is respected properly.
|
23
|
+
owner_class.named_scope(name)
|
24
|
+
owner_class.scopes[name] = lambda do |model, *states|
|
25
|
+
machine_states = model.state_machine(machine_name).states
|
26
|
+
values = states.flatten.map {|state| machine_states.fetch(state).value}
|
27
|
+
|
28
|
+
::ActiveRecord::NamedScope::Scope.new(model, :conditions => scope.call(values))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Prevent the Machine class from wrapping the scope
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def invalidate(object, attribute, message, values = [])
|
37
|
+
if defined?(I18n)
|
38
|
+
super
|
39
|
+
else
|
40
|
+
object.errors.add(self.attribute(attribute), generate_message(message, values))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def translate(klass, key, value)
|
45
|
+
if defined?(I18n)
|
46
|
+
super
|
47
|
+
else
|
48
|
+
value ? value.to_s.humanize.downcase : 'nil'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def supports_observers?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def supports_validations?
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def supports_mass_assignment_security?
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
def i18n_scope(klass)
|
65
|
+
:activerecord
|
66
|
+
end
|
67
|
+
|
68
|
+
def action_hook
|
69
|
+
action == :save ? :create_or_update : super
|
70
|
+
end
|
71
|
+
|
72
|
+
def filter_attributes(object, attributes)
|
73
|
+
object.send(:remove_attributes_protected_from_mass_assignment, attributes)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
version '2.0 - 2.2.x' do
|
78
|
+
def self.active?
|
79
|
+
::ActiveRecord::VERSION::MAJOR == 2 && ::ActiveRecord::VERSION::MINOR < 3
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_error_message_options(object, attribute, message)
|
83
|
+
{:default => @messages[message]}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
version '2.0 - 2.3.1' do
|
88
|
+
def self.active?
|
89
|
+
::ActiveRecord::VERSION::MAJOR == 2 && (::ActiveRecord::VERSION::MINOR < 3 || ::ActiveRecord::VERSION::TINY < 2)
|
90
|
+
end
|
91
|
+
|
92
|
+
def ancestors_for(klass)
|
93
|
+
klass.self_and_descendents_from_active_record
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
version '2.0 - 2.3.4' do
|
98
|
+
def self.active?
|
99
|
+
::ActiveRecord::VERSION::MAJOR == 2 && (::ActiveRecord::VERSION::MINOR < 3 || ::ActiveRecord::VERSION::TINY < 5)
|
100
|
+
end
|
101
|
+
|
102
|
+
def load_i18n_version
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
version '2.0.x' do
|
107
|
+
def self.active?
|
108
|
+
::ActiveRecord::VERSION::MAJOR == 2 && ::ActiveRecord::VERSION::MINOR == 0
|
109
|
+
end
|
110
|
+
|
111
|
+
def supports_dirty_tracking?(object)
|
112
|
+
false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
version '2.1.x - 2.3.x' do
|
117
|
+
def self.active?
|
118
|
+
::ActiveRecord::VERSION::MAJOR == 2 && ::ActiveRecord::VERSION::MINOR > 0
|
119
|
+
end
|
120
|
+
|
121
|
+
def supports_dirty_tracking?(object)
|
122
|
+
object.respond_to?("#{attribute}_changed?")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
version '2.3.2 - 2.3.x' do
|
127
|
+
def self.active?
|
128
|
+
::ActiveRecord::VERSION::MAJOR == 2 && ::ActiveRecord::VERSION::MINOR == 3 && ::ActiveRecord::VERSION::TINY >= 2
|
129
|
+
end
|
130
|
+
|
131
|
+
def ancestors_for(klass)
|
132
|
+
klass.self_and_descendants_from_active_record
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
version '3.0.x' do
|
137
|
+
def self.active?
|
138
|
+
::ActiveRecord::VERSION::MAJOR == 3 && ::ActiveRecord::VERSION::MINOR == 0
|
139
|
+
end
|
140
|
+
|
141
|
+
def define_action_hook
|
142
|
+
# +around+ callbacks don't have direct access to results until AS 3.1
|
143
|
+
owner_class.set_callback(:save, :after, 'value', :prepend => true) if action_hook == :save
|
144
|
+
super
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|