activemodel 3.0.0.beta4 → 3.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|