activemodel 3.0.0.beta4 → 3.0.pre
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 +1 -39
- data/MIT-LICENSE +1 -1
- data/README +16 -200
- data/lib/active_model.rb +19 -28
- data/lib/active_model/attribute_methods.rb +27 -142
- data/lib/active_model/conversion.rb +1 -37
- data/lib/active_model/dirty.rb +12 -51
- data/lib/active_model/errors.rb +22 -146
- data/lib/active_model/lint.rb +14 -48
- data/lib/active_model/locale/en.yml +23 -26
- data/lib/active_model/naming.rb +5 -41
- data/lib/active_model/observing.rb +16 -35
- data/lib/active_model/serialization.rb +0 -57
- data/lib/active_model/serializers/json.rb +8 -13
- data/lib/active_model/serializers/xml.rb +123 -63
- data/lib/active_model/state_machine.rb +70 -0
- data/lib/active_model/state_machine/event.rb +62 -0
- data/lib/active_model/state_machine/machine.rb +75 -0
- data/lib/active_model/state_machine/state.rb +47 -0
- data/lib/active_model/state_machine/state_transition.rb +40 -0
- data/lib/active_model/test_case.rb +2 -0
- data/lib/active_model/validations.rb +62 -125
- data/lib/active_model/validations/acceptance.rb +18 -23
- data/lib/active_model/validations/confirmation.rb +10 -14
- data/lib/active_model/validations/exclusion.rb +13 -15
- data/lib/active_model/validations/format.rb +24 -26
- data/lib/active_model/validations/inclusion.rb +13 -15
- data/lib/active_model/validations/length.rb +65 -61
- data/lib/active_model/validations/numericality.rb +58 -76
- data/lib/active_model/validations/presence.rb +8 -8
- data/lib/active_model/validations/with.rb +22 -90
- data/lib/active_model/validations_repair_helper.rb +35 -0
- data/lib/active_model/version.rb +2 -3
- metadata +19 -63
- data/lib/active_model/callbacks.rb +0 -134
- data/lib/active_model/railtie.rb +0 -2
- data/lib/active_model/translation.rb +0 -60
- data/lib/active_model/validations/validates.rb +0 -108
- data/lib/active_model/validator.rb +0 -183
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module StateMachine
|
3
|
+
autoload :Event, 'active_model/state_machine/event'
|
4
|
+
autoload :Machine, 'active_model/state_machine/machine'
|
5
|
+
autoload :State, 'active_model/state_machine/state'
|
6
|
+
autoload :StateTransition, 'active_model/state_machine/state_transition'
|
7
|
+
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
class InvalidTransition < Exception
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def inherited(klass)
|
15
|
+
super
|
16
|
+
klass.state_machines = state_machines
|
17
|
+
end
|
18
|
+
|
19
|
+
def state_machines
|
20
|
+
@state_machines ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def state_machines=(value)
|
24
|
+
@state_machines = value ? value.dup : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def state_machine(name = nil, options = {}, &block)
|
28
|
+
if name.is_a?(Hash)
|
29
|
+
options = name
|
30
|
+
name = nil
|
31
|
+
end
|
32
|
+
name ||= :default
|
33
|
+
state_machines[name] ||= Machine.new(self, name)
|
34
|
+
block ? state_machines[name].update(options, &block) : state_machines[name]
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_state_query_method(state_name)
|
38
|
+
name = "#{state_name}?"
|
39
|
+
undef_method(name) if method_defined?(name)
|
40
|
+
class_eval "def #{name}; current_state.to_s == %(#{state_name}) end"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def current_state(name = nil, new_state = nil, persist = false)
|
45
|
+
sm = self.class.state_machine(name)
|
46
|
+
ivar = sm.current_state_variable
|
47
|
+
if name && new_state
|
48
|
+
if persist && respond_to?(:write_state)
|
49
|
+
write_state(sm, new_state)
|
50
|
+
end
|
51
|
+
|
52
|
+
if respond_to?(:write_state_without_persistence)
|
53
|
+
write_state_without_persistence(sm, new_state)
|
54
|
+
end
|
55
|
+
|
56
|
+
instance_variable_set(ivar, new_state)
|
57
|
+
else
|
58
|
+
instance_variable_set(ivar, nil) unless instance_variable_defined?(ivar)
|
59
|
+
value = instance_variable_get(ivar)
|
60
|
+
return value if value
|
61
|
+
|
62
|
+
if respond_to?(:read_state)
|
63
|
+
value = instance_variable_set(ivar, read_state(sm))
|
64
|
+
end
|
65
|
+
|
66
|
+
value || sm.initial_state
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module StateMachine
|
3
|
+
class Event
|
4
|
+
attr_reader :name, :success
|
5
|
+
|
6
|
+
def initialize(machine, name, options = {}, &block)
|
7
|
+
@machine, @name, @transitions = machine, name, []
|
8
|
+
if machine
|
9
|
+
machine.klass.send(:define_method, "#{name}!") do |*args|
|
10
|
+
machine.fire_event(name, self, true, *args)
|
11
|
+
end
|
12
|
+
|
13
|
+
machine.klass.send(:define_method, name.to_s) do |*args|
|
14
|
+
machine.fire_event(name, self, false, *args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
update(options, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def fire(obj, to_state = nil, *args)
|
21
|
+
transitions = @transitions.select { |t| t.from == obj.current_state(@machine ? @machine.name : nil) }
|
22
|
+
raise InvalidTransition if transitions.size == 0
|
23
|
+
|
24
|
+
next_state = nil
|
25
|
+
transitions.each do |transition|
|
26
|
+
next if to_state && !Array(transition.to).include?(to_state)
|
27
|
+
if transition.perform(obj)
|
28
|
+
next_state = to_state || Array(transition.to).first
|
29
|
+
transition.execute(obj, *args)
|
30
|
+
break
|
31
|
+
end
|
32
|
+
end
|
33
|
+
next_state
|
34
|
+
end
|
35
|
+
|
36
|
+
def transitions_from_state?(state)
|
37
|
+
@transitions.any? { |t| t.from? state }
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(event)
|
41
|
+
if event.is_a? Symbol
|
42
|
+
name == event
|
43
|
+
else
|
44
|
+
name == event.name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def update(options = {}, &block)
|
49
|
+
if options.key?(:success) then @success = options[:success] end
|
50
|
+
if block then instance_eval(&block) end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def transitions(trans_opts)
|
56
|
+
Array(trans_opts[:from]).each do |s|
|
57
|
+
@transitions << StateTransition.new(trans_opts.merge({:from => s.to_sym}))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module StateMachine
|
3
|
+
class Machine
|
4
|
+
attr_writer :initial_state
|
5
|
+
attr_accessor :states, :events, :state_index
|
6
|
+
attr_reader :klass, :name
|
7
|
+
|
8
|
+
def initialize(klass, name, options = {}, &block)
|
9
|
+
@klass, @name, @states, @state_index, @events = klass, name, [], {}, {}
|
10
|
+
update(options, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initial_state
|
14
|
+
@initial_state ||= (states.first ? states.first.name : nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(options = {}, &block)
|
18
|
+
if options.key?(:initial) then @initial_state = options[:initial] end
|
19
|
+
if block then instance_eval(&block) end
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def fire_event(event, record, persist, *args)
|
24
|
+
state_index[record.current_state(@name)].call_action(:exit, record)
|
25
|
+
if new_state = @events[event].fire(record, *args)
|
26
|
+
state_index[new_state].call_action(:enter, record)
|
27
|
+
|
28
|
+
if record.respond_to?(event_fired_callback)
|
29
|
+
record.send(event_fired_callback, record.current_state, new_state)
|
30
|
+
end
|
31
|
+
|
32
|
+
record.current_state(@name, new_state, persist)
|
33
|
+
record.send(@events[event].success) if @events[event].success
|
34
|
+
true
|
35
|
+
else
|
36
|
+
if record.respond_to?(event_failed_callback)
|
37
|
+
record.send(event_failed_callback, event)
|
38
|
+
end
|
39
|
+
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def states_for_select
|
45
|
+
states.map { |st| [st.display_name, st.name.to_s] }
|
46
|
+
end
|
47
|
+
|
48
|
+
def events_for(state)
|
49
|
+
events = @events.values.select { |event| event.transitions_from_state?(state) }
|
50
|
+
events.map! { |event| event.name }
|
51
|
+
end
|
52
|
+
|
53
|
+
def current_state_variable
|
54
|
+
"@#{@name}_current_state"
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def state(name, options = {})
|
59
|
+
@states << (state_index[name] ||= State.new(name, :machine => self)).update(options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def event(name, options = {}, &block)
|
63
|
+
(@events[name] ||= Event.new(self, name)).update(options, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def event_fired_callback
|
67
|
+
@event_fired_callback ||= (@name == :default ? '' : "#{@name}_") + 'event_fired'
|
68
|
+
end
|
69
|
+
|
70
|
+
def event_failed_callback
|
71
|
+
@event_failed_callback ||= (@name == :default ? '' : "#{@name}_") + 'event_failed'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module StateMachine
|
3
|
+
class State
|
4
|
+
attr_reader :name, :options
|
5
|
+
|
6
|
+
def initialize(name, options = {})
|
7
|
+
@name = name
|
8
|
+
if machine = options.delete(:machine)
|
9
|
+
machine.klass.define_state_query_method(name)
|
10
|
+
end
|
11
|
+
update(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(state)
|
15
|
+
if state.is_a? Symbol
|
16
|
+
name == state
|
17
|
+
else
|
18
|
+
name == state.name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def call_action(action, record)
|
23
|
+
action = @options[action]
|
24
|
+
case action
|
25
|
+
when Symbol, String
|
26
|
+
record.send(action)
|
27
|
+
when Proc
|
28
|
+
action.call(record)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def display_name
|
33
|
+
@display_name ||= name.to_s.gsub(/_/, ' ').capitalize
|
34
|
+
end
|
35
|
+
|
36
|
+
def for_select
|
37
|
+
[display_name, name.to_s]
|
38
|
+
end
|
39
|
+
|
40
|
+
def update(options = {})
|
41
|
+
if options.key?(:display) then @display_name = options.delete(:display) end
|
42
|
+
@options = options
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module StateMachine
|
3
|
+
class StateTransition
|
4
|
+
attr_reader :from, :to, :options
|
5
|
+
|
6
|
+
def initialize(opts)
|
7
|
+
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
|
8
|
+
@options = opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform(obj)
|
12
|
+
case @guard
|
13
|
+
when Symbol, String
|
14
|
+
obj.send(@guard)
|
15
|
+
when Proc
|
16
|
+
@guard.call(obj)
|
17
|
+
else
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(obj, *args)
|
23
|
+
case @on_transition
|
24
|
+
when Symbol, String
|
25
|
+
obj.send(@on_transition, *args)
|
26
|
+
when Proc
|
27
|
+
@on_transition.call(obj, *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(obj)
|
32
|
+
@from == obj.from && @to == obj.to
|
33
|
+
end
|
34
|
+
|
35
|
+
def from?(value)
|
36
|
+
@from == value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,103 +1,23 @@
|
|
1
1
|
require 'active_support/core_ext/array/extract_options'
|
2
|
-
require 'active_support/core_ext/array/wrap'
|
3
|
-
require 'active_support/core_ext/class/attribute'
|
4
2
|
require 'active_support/core_ext/hash/keys'
|
5
|
-
require 'active_model/errors'
|
6
3
|
|
7
4
|
module ActiveModel
|
8
|
-
|
9
|
-
# Provides a full validation framework to your objects.
|
10
|
-
#
|
11
|
-
# A minimal implementation could be:
|
12
|
-
#
|
13
|
-
# class Person
|
14
|
-
# include ActiveModel::Validations
|
15
|
-
#
|
16
|
-
# attr_accessor :first_name, :last_name
|
17
|
-
#
|
18
|
-
# validates_each :first_name, :last_name do |record, attr, value|
|
19
|
-
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
20
|
-
# end
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# Which provides you with the full standard validation stack that you
|
24
|
-
# know from ActiveRecord.
|
25
|
-
#
|
26
|
-
# person = Person.new
|
27
|
-
# person.valid?
|
28
|
-
# #=> true
|
29
|
-
# person.invalid?
|
30
|
-
# #=> false
|
31
|
-
# person.first_name = 'zoolander'
|
32
|
-
# person.valid?
|
33
|
-
# #=> false
|
34
|
-
# person.invalid?
|
35
|
-
# #=> true
|
36
|
-
# person.errors
|
37
|
-
# #=> #<OrderedHash {:first_name=>["starts with z."]}>
|
38
|
-
#
|
39
|
-
# Note that ActiveModel::Validations automatically adds an +errors+ method
|
40
|
-
# to your instances initialized with a new ActiveModel::Errors object, so
|
41
|
-
# there is no need for you to add this manually.
|
42
|
-
#
|
43
5
|
module Validations
|
44
6
|
extend ActiveSupport::Concern
|
45
7
|
include ActiveSupport::Callbacks
|
46
8
|
|
47
9
|
included do
|
48
|
-
extend ActiveModel::Translation
|
49
|
-
|
50
|
-
extend HelperMethods
|
51
|
-
include HelperMethods
|
52
|
-
|
53
10
|
define_callbacks :validate, :scope => :name
|
54
|
-
|
55
|
-
attr_accessor :validation_context
|
56
|
-
|
57
|
-
class_attribute :_validators
|
58
|
-
self._validators = Hash.new { |h,k| h[k] = [] }
|
59
11
|
end
|
60
12
|
|
61
13
|
module ClassMethods
|
62
|
-
# Validates each attribute against a block.
|
63
|
-
#
|
64
|
-
# class Person
|
65
|
-
# include ActiveModel::Validations
|
66
|
-
#
|
67
|
-
# attr_accessor :first_name, :last_name
|
68
|
-
#
|
69
|
-
# validates_each :first_name, :last_name do |record, attr, value|
|
70
|
-
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
71
|
-
# end
|
72
|
-
# end
|
73
|
-
#
|
74
|
-
# Options:
|
75
|
-
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>,
|
76
|
-
# other options <tt>:create</tt>, <tt>:update</tt>).
|
77
|
-
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
|
78
|
-
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
|
79
|
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
80
|
-
# occur (e.g. <tt>:if => :allow_validation</tt>, or
|
81
|
-
# <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
82
|
-
# method, proc or string should return or evaluate to a true or false value.
|
83
|
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
84
|
-
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or
|
85
|
-
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
86
|
-
# method, proc or string should return or evaluate to a true or false value.
|
87
|
-
def validates_each(*attr_names, &block)
|
88
|
-
options = attr_names.extract_options!.symbolize_keys
|
89
|
-
validates_with BlockValidator, options.merge(:attributes => attr_names.flatten), &block
|
90
|
-
end
|
91
|
-
|
92
14
|
# Adds a validation method or block to the class. This is useful when
|
93
15
|
# overriding the +validate+ instance method becomes too unwieldly and
|
94
16
|
# you're looking for more descriptive declaration of your validations.
|
95
17
|
#
|
96
18
|
# This can be done with a symbol pointing to a method:
|
97
19
|
#
|
98
|
-
# class Comment
|
99
|
-
# include ActiveModel::Validations
|
100
|
-
#
|
20
|
+
# class Comment < ActiveRecord::Base
|
101
21
|
# validate :must_be_friends
|
102
22
|
#
|
103
23
|
# def must_be_friends
|
@@ -107,9 +27,7 @@ module ActiveModel
|
|
107
27
|
#
|
108
28
|
# Or with a block which is passed the current record to be validated:
|
109
29
|
#
|
110
|
-
# class Comment
|
111
|
-
# include ActiveModel::Validations
|
112
|
-
#
|
30
|
+
# class Comment < ActiveRecord::Base
|
113
31
|
# validate do |comment|
|
114
32
|
# comment.must_be_friends
|
115
33
|
# end
|
@@ -119,29 +37,48 @@ module ActiveModel
|
|
119
37
|
# end
|
120
38
|
# end
|
121
39
|
#
|
40
|
+
# This usage applies to +validate_on_create+ and +validate_on_update as well+.
|
41
|
+
|
42
|
+
# Validates each attribute against a block.
|
43
|
+
#
|
44
|
+
# class Person < ActiveRecord::Base
|
45
|
+
# validates_each :first_name, :last_name do |record, attr, value|
|
46
|
+
# record.errors.add attr, 'starts with z.' if value[0] == ?z
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Options:
|
51
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
52
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
|
53
|
+
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
|
54
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
55
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
56
|
+
# method, proc or string should return or evaluate to a true or false value.
|
57
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
58
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
59
|
+
# method, proc or string should return or evaluate to a true or false value.
|
60
|
+
def validates_each(*attrs)
|
61
|
+
options = attrs.extract_options!.symbolize_keys
|
62
|
+
attrs = attrs.flatten
|
63
|
+
|
64
|
+
# Declare the validation.
|
65
|
+
validate options do |record|
|
66
|
+
attrs.each do |attr|
|
67
|
+
value = record.send(:read_attribute_for_validation, attr)
|
68
|
+
next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
69
|
+
yield record, attr, value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
122
74
|
def validate(*args, &block)
|
123
75
|
options = args.last
|
124
76
|
if options.is_a?(Hash) && options.key?(:on)
|
125
|
-
options[:if] = Array
|
126
|
-
options[:if] << "
|
77
|
+
options[:if] = Array(options[:if])
|
78
|
+
options[:if] << "@_on_validate == :#{options[:on]}"
|
127
79
|
end
|
128
80
|
set_callback(:validate, *args, &block)
|
129
81
|
end
|
130
|
-
|
131
|
-
# List all validators that being used to validate the model using +validates_with+
|
132
|
-
# method.
|
133
|
-
def validators
|
134
|
-
_validators.values.flatten.uniq
|
135
|
-
end
|
136
|
-
|
137
|
-
# List all validators that being used to validate a specific attribute.
|
138
|
-
def validators_on(attribute)
|
139
|
-
_validators[attribute.to_sym]
|
140
|
-
end
|
141
|
-
|
142
|
-
def attribute_method?(attribute)
|
143
|
-
method_defined?(attribute)
|
144
|
-
end
|
145
82
|
end
|
146
83
|
|
147
84
|
# Returns the Errors object that holds all information about attribute error messages.
|
@@ -150,38 +87,38 @@ module ActiveModel
|
|
150
87
|
end
|
151
88
|
|
152
89
|
# Runs all the specified validations and returns true if no errors were added otherwise false.
|
153
|
-
|
154
|
-
# defined on the validations using :on).
|
155
|
-
def valid?(context = nil)
|
156
|
-
current_context, self.validation_context = validation_context, context
|
90
|
+
def valid?
|
157
91
|
errors.clear
|
158
92
|
_run_validate_callbacks
|
159
93
|
errors.empty?
|
160
|
-
ensure
|
161
|
-
self.validation_context = current_context
|
162
94
|
end
|
163
95
|
|
164
96
|
# Performs the opposite of <tt>valid?</tt>. Returns true if errors were added, false otherwise.
|
165
|
-
def invalid?
|
166
|
-
!valid?
|
97
|
+
def invalid?
|
98
|
+
!valid?
|
167
99
|
end
|
168
100
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
101
|
+
protected
|
102
|
+
# Hook method defining how an attribute value should be retieved. By default this is assumed
|
103
|
+
# to be an instance named after the attribute. Override this method in subclasses should you
|
104
|
+
# need to retrieve the value for a given attribute differently e.g.
|
105
|
+
# class MyClass
|
106
|
+
# include ActiveModel::Validations
|
107
|
+
#
|
108
|
+
# def initialize(data = {})
|
109
|
+
# @data = data
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# private
|
113
|
+
#
|
114
|
+
# def read_attribute_for_validation(key)
|
115
|
+
# @data[key]
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
def read_attribute_for_validation(key)
|
120
|
+
send(key)
|
121
|
+
end
|
185
122
|
end
|
186
123
|
end
|
187
124
|
|