activemodel 3.0.pre → 3.0.0.rc
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 +44 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +184 -0
- data/lib/active_model.rb +29 -19
- data/lib/active_model/attribute_methods.rb +167 -46
- data/lib/active_model/callbacks.rb +134 -0
- data/lib/active_model/conversion.rb +41 -1
- data/lib/active_model/deprecated_error_methods.rb +1 -1
- data/lib/active_model/dirty.rb +56 -12
- data/lib/active_model/errors.rb +205 -46
- data/lib/active_model/lint.rb +53 -17
- data/lib/active_model/locale/en.yml +26 -23
- data/lib/active_model/mass_assignment_security.rb +160 -0
- data/lib/active_model/mass_assignment_security/permission_set.rb +40 -0
- data/lib/active_model/mass_assignment_security/sanitizer.rb +23 -0
- data/lib/active_model/naming.rb +70 -5
- data/lib/active_model/observing.rb +40 -16
- data/lib/active_model/railtie.rb +2 -0
- data/lib/active_model/serialization.rb +59 -0
- data/lib/active_model/serializers/json.rb +17 -11
- data/lib/active_model/serializers/xml.rb +66 -123
- data/lib/active_model/test_case.rb +0 -2
- data/lib/active_model/translation.rb +64 -0
- data/lib/active_model/validations.rb +150 -68
- data/lib/active_model/validations/acceptance.rb +53 -33
- data/lib/active_model/validations/callbacks.rb +57 -0
- data/lib/active_model/validations/confirmation.rb +41 -23
- data/lib/active_model/validations/exclusion.rb +18 -13
- data/lib/active_model/validations/format.rb +28 -24
- data/lib/active_model/validations/inclusion.rb +18 -13
- data/lib/active_model/validations/length.rb +67 -65
- data/lib/active_model/validations/numericality.rb +83 -58
- data/lib/active_model/validations/presence.rb +10 -8
- data/lib/active_model/validations/validates.rb +110 -0
- data/lib/active_model/validations/with.rb +90 -23
- data/lib/active_model/validator.rb +186 -0
- data/lib/active_model/version.rb +3 -2
- metadata +79 -20
- data/README +0 -21
- data/lib/active_model/state_machine.rb +0 -70
- data/lib/active_model/state_machine/event.rb +0 -62
- data/lib/active_model/state_machine/machine.rb +0 -75
- data/lib/active_model/state_machine/state.rb +0 -47
- data/lib/active_model/state_machine/state_transition.rb +0 -40
- data/lib/active_model/validations_repair_helper.rb +0 -35
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
|
5
|
+
# == Active Model Translation
|
6
|
+
#
|
7
|
+
# Provides integration between your object and the Rails internationalization
|
8
|
+
# (i18n) framework.
|
9
|
+
#
|
10
|
+
# A minimal implementation could be:
|
11
|
+
#
|
12
|
+
# class TranslatedPerson
|
13
|
+
# extend ActiveModel::Translation
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# TranslatedPerson.human_attribute_name('my_attribute')
|
17
|
+
# #=> "My attribute"
|
18
|
+
#
|
19
|
+
# This also provides the required class methods for hooking into the
|
20
|
+
# Rails internationalization API, including being able to define a
|
21
|
+
# class based i18n_scope and lookup_ancestors to find translations in
|
22
|
+
# parent classes.
|
23
|
+
module Translation
|
24
|
+
include ActiveModel::Naming
|
25
|
+
|
26
|
+
# Returns the i18n_scope for the class. Overwrite if you want custom lookup.
|
27
|
+
def i18n_scope
|
28
|
+
:activemodel
|
29
|
+
end
|
30
|
+
|
31
|
+
# When localizing a string, it goes through the lookup returned by this
|
32
|
+
# method, which is used in ActiveModel::Name#human,
|
33
|
+
# ActiveModel::Errors#full_messages and
|
34
|
+
# ActiveModel::Translation#human_attribute_name.
|
35
|
+
def lookup_ancestors
|
36
|
+
self.ancestors.select { |x| x.respond_to?(:model_name) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Transforms attribute names into a more human format, such as "First name"
|
40
|
+
# instead of "first_name".
|
41
|
+
#
|
42
|
+
# Person.human_attribute_name("first_name") # => "First name"
|
43
|
+
#
|
44
|
+
# Specify +options+ with additional translating options.
|
45
|
+
def human_attribute_name(attribute, options = {})
|
46
|
+
defaults = lookup_ancestors.map do |klass|
|
47
|
+
:"#{self.i18n_scope}.attributes.#{klass.model_name.underscore}.#{attribute}"
|
48
|
+
end
|
49
|
+
|
50
|
+
defaults << :"attributes.#{attribute}"
|
51
|
+
defaults << options.delete(:default) if options[:default]
|
52
|
+
defaults << attribute.to_s.humanize
|
53
|
+
|
54
|
+
options.reverse_merge! :count => 1, :default => defaults
|
55
|
+
I18n.translate(defaults.shift, options)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Model.human_name is deprecated. Use Model.model_name.human instead.
|
59
|
+
def human_name(*args)
|
60
|
+
ActiveSupport::Deprecation.warn("human_name has been deprecated, please use model_name.human instead", caller[0,5])
|
61
|
+
model_name.human(*args)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,23 +1,105 @@
|
|
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'
|
2
4
|
require 'active_support/core_ext/hash/keys'
|
5
|
+
require 'active_model/errors'
|
6
|
+
require 'active_model/validations/callbacks'
|
3
7
|
|
4
8
|
module ActiveModel
|
9
|
+
|
10
|
+
# == Active Model Validations
|
11
|
+
#
|
12
|
+
# Provides a full validation framework to your objects.
|
13
|
+
#
|
14
|
+
# A minimal implementation could be:
|
15
|
+
#
|
16
|
+
# class Person
|
17
|
+
# include ActiveModel::Validations
|
18
|
+
#
|
19
|
+
# attr_accessor :first_name, :last_name
|
20
|
+
#
|
21
|
+
# validates_each :first_name, :last_name do |record, attr, value|
|
22
|
+
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# Which provides you with the full standard validation stack that you
|
27
|
+
# know from ActiveRecord.
|
28
|
+
#
|
29
|
+
# person = Person.new
|
30
|
+
# person.valid?
|
31
|
+
# #=> true
|
32
|
+
# person.invalid?
|
33
|
+
# #=> false
|
34
|
+
# person.first_name = 'zoolander'
|
35
|
+
# person.valid?
|
36
|
+
# #=> false
|
37
|
+
# person.invalid?
|
38
|
+
# #=> true
|
39
|
+
# person.errors
|
40
|
+
# #=> #<OrderedHash {:first_name=>["starts with z."]}>
|
41
|
+
#
|
42
|
+
# Note that ActiveModel::Validations automatically adds an +errors+ method
|
43
|
+
# to your instances initialized with a new ActiveModel::Errors object, so
|
44
|
+
# there is no need for you to do this manually.
|
45
|
+
#
|
5
46
|
module Validations
|
6
47
|
extend ActiveSupport::Concern
|
7
48
|
include ActiveSupport::Callbacks
|
8
49
|
|
9
50
|
included do
|
51
|
+
extend ActiveModel::Translation
|
52
|
+
|
53
|
+
extend HelperMethods
|
54
|
+
include HelperMethods
|
55
|
+
|
56
|
+
attr_accessor :validation_context
|
10
57
|
define_callbacks :validate, :scope => :name
|
58
|
+
|
59
|
+
class_attribute :_validators
|
60
|
+
self._validators = Hash.new { |h,k| h[k] = [] }
|
11
61
|
end
|
12
62
|
|
13
63
|
module ClassMethods
|
64
|
+
# Validates each attribute against a block.
|
65
|
+
#
|
66
|
+
# class Person
|
67
|
+
# include ActiveModel::Validations
|
68
|
+
#
|
69
|
+
# attr_accessor :first_name, :last_name
|
70
|
+
#
|
71
|
+
# validates_each :first_name, :last_name do |record, attr, value|
|
72
|
+
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# Options:
|
77
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is
|
78
|
+
# <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
79
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
|
80
|
+
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
|
81
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
82
|
+
# if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
|
83
|
+
# or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
84
|
+
# proc or string should return or evaluate to a true or false value.
|
85
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
86
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or
|
87
|
+
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
88
|
+
# method, proc or string should return or evaluate to a true or false value.
|
89
|
+
def validates_each(*attr_names, &block)
|
90
|
+
options = attr_names.extract_options!.symbolize_keys
|
91
|
+
validates_with BlockValidator, options.merge(:attributes => attr_names.flatten), &block
|
92
|
+
end
|
93
|
+
|
14
94
|
# Adds a validation method or block to the class. This is useful when
|
15
|
-
# overriding the +validate+ instance method becomes too
|
95
|
+
# overriding the +validate+ instance method becomes too unwieldy and
|
16
96
|
# you're looking for more descriptive declaration of your validations.
|
17
97
|
#
|
18
98
|
# This can be done with a symbol pointing to a method:
|
19
99
|
#
|
20
|
-
# class Comment
|
100
|
+
# class Comment
|
101
|
+
# include ActiveModel::Validations
|
102
|
+
#
|
21
103
|
# validate :must_be_friends
|
22
104
|
#
|
23
105
|
# def must_be_friends
|
@@ -25,9 +107,11 @@ module ActiveModel
|
|
25
107
|
# end
|
26
108
|
# end
|
27
109
|
#
|
28
|
-
# Or with a block which is passed the current record to be validated:
|
110
|
+
# Or with a block which is passed with the current record to be validated:
|
111
|
+
#
|
112
|
+
# class Comment
|
113
|
+
# include ActiveModel::Validations
|
29
114
|
#
|
30
|
-
# class Comment < ActiveRecord::Base
|
31
115
|
# validate do |comment|
|
32
116
|
# comment.must_be_friends
|
33
117
|
# end
|
@@ -37,48 +121,37 @@ module ActiveModel
|
|
37
121
|
# end
|
38
122
|
# end
|
39
123
|
#
|
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
|
-
|
74
124
|
def validate(*args, &block)
|
75
125
|
options = args.last
|
76
126
|
if options.is_a?(Hash) && options.key?(:on)
|
77
|
-
options[:if] = Array(options[:if])
|
78
|
-
options[:if] << "
|
127
|
+
options[:if] = Array.wrap(options[:if])
|
128
|
+
options[:if] << "validation_context == :#{options[:on]}"
|
79
129
|
end
|
80
130
|
set_callback(:validate, *args, &block)
|
81
131
|
end
|
132
|
+
|
133
|
+
# List all validators that are being used to validate the model using
|
134
|
+
# +validates_with+ method.
|
135
|
+
def validators
|
136
|
+
_validators.values.flatten.uniq
|
137
|
+
end
|
138
|
+
|
139
|
+
# List all validators that being used to validate a specific attribute.
|
140
|
+
def validators_on(attribute)
|
141
|
+
_validators[attribute.to_sym]
|
142
|
+
end
|
143
|
+
|
144
|
+
# Check if method is an attribute method or not.
|
145
|
+
def attribute_method?(attribute)
|
146
|
+
method_defined?(attribute)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Copy validators on inheritance.
|
150
|
+
def inherited(base)
|
151
|
+
dup = _validators.dup
|
152
|
+
base._validators = dup.each { |k, v| dup[k] = v.dup }
|
153
|
+
super
|
154
|
+
end
|
82
155
|
end
|
83
156
|
|
84
157
|
# Returns the Errors object that holds all information about attribute error messages.
|
@@ -86,39 +159,48 @@ module ActiveModel
|
|
86
159
|
@errors ||= Errors.new(self)
|
87
160
|
end
|
88
161
|
|
89
|
-
# Runs all the specified validations and returns true if no errors were added
|
90
|
-
|
162
|
+
# Runs all the specified validations and returns true if no errors were added
|
163
|
+
# otherwise false. Context can optionally be supplied to define which callbacks
|
164
|
+
# to test against (the context is defined on the validations using :on).
|
165
|
+
def valid?(context = nil)
|
166
|
+
current_context, self.validation_context = validation_context, context
|
91
167
|
errors.clear
|
92
|
-
|
93
|
-
|
168
|
+
run_validations!
|
169
|
+
ensure
|
170
|
+
self.validation_context = current_context
|
94
171
|
end
|
95
172
|
|
96
|
-
# Performs the opposite of <tt>valid?</tt>. Returns true if errors were added,
|
97
|
-
|
98
|
-
|
173
|
+
# Performs the opposite of <tt>valid?</tt>. Returns true if errors were added,
|
174
|
+
# false otherwise.
|
175
|
+
def invalid?(context = nil)
|
176
|
+
!valid?(context)
|
99
177
|
end
|
100
178
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
179
|
+
# Hook method defining how an attribute value should be retrieved. By default
|
180
|
+
# this is assumed to be an instance named after the attribute. Override this
|
181
|
+
# method in subclasses should you need to retrieve the value for a given
|
182
|
+
# attribute differently:
|
183
|
+
#
|
184
|
+
# class MyClass
|
185
|
+
# include ActiveModel::Validations
|
186
|
+
#
|
187
|
+
# def initialize(data = {})
|
188
|
+
# @data = data
|
189
|
+
# end
|
190
|
+
#
|
191
|
+
# def read_attribute_for_validation(key)
|
192
|
+
# @data[key]
|
193
|
+
# end
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
alias :read_attribute_for_validation :send
|
197
|
+
|
198
|
+
protected
|
199
|
+
|
200
|
+
def run_validations!
|
201
|
+
_run_validate_callbacks
|
202
|
+
errors.empty?
|
203
|
+
end
|
122
204
|
end
|
123
205
|
end
|
124
206
|
|
@@ -1,47 +1,67 @@
|
|
1
1
|
module ActiveModel
|
2
|
+
|
3
|
+
# == Active Model Acceptance Validator
|
2
4
|
module Validations
|
3
|
-
|
4
|
-
|
5
|
+
class AcceptanceValidator < EachValidator
|
6
|
+
def initialize(options)
|
7
|
+
super(options.reverse_merge(:allow_nil => true, :accept => "1"))
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_each(record, attribute, value)
|
11
|
+
unless value == options[:accept]
|
12
|
+
record.errors.add(attribute, :accepted, options.except(:accept, :allow_nil))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup(klass)
|
17
|
+
# Note: instance_methods.map(&:to_s) is important for 1.9 compatibility
|
18
|
+
# as instance_methods returns symbols unlike 1.8 which returns strings.
|
19
|
+
attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
|
20
|
+
attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
|
21
|
+
klass.send(:attr_reader, *attr_readers)
|
22
|
+
klass.send(:attr_writer, *attr_writers)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module HelperMethods
|
27
|
+
# Encapsulates the pattern of wanting to validate the acceptance of a
|
28
|
+
# terms of service check box (or similar agreement). Example:
|
5
29
|
#
|
6
30
|
# class Person < ActiveRecord::Base
|
7
31
|
# validates_acceptance_of :terms_of_service
|
8
32
|
# validates_acceptance_of :eula, :message => "must be abided"
|
9
33
|
# end
|
10
34
|
#
|
11
|
-
# If the database column does not exist, the +terms_of_service+ attribute
|
12
|
-
# performed only if +terms_of_service+
|
35
|
+
# If the database column does not exist, the +terms_of_service+ attribute
|
36
|
+
# is entirely virtual. This check is performed only if +terms_of_service+
|
37
|
+
# is not +nil+ and by default on save.
|
13
38
|
#
|
14
39
|
# Configuration options:
|
15
|
-
# * <tt>:message</tt> - A custom error message (default is: "must be
|
16
|
-
#
|
17
|
-
# * <tt>:
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
40
|
+
# * <tt>:message</tt> - A custom error message (default is: "must be
|
41
|
+
# accepted").
|
42
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is
|
43
|
+
# <tt>:save</tt>, other options are <tt>:create</tt> and
|
44
|
+
# <tt>:update</tt>).
|
45
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default
|
46
|
+
# is true).
|
47
|
+
# * <tt>:accept</tt> - Specifies value that is considered accepted.
|
48
|
+
# The default value is a string "1", which makes it easy to relate to
|
49
|
+
# an HTML checkbox. This should be set to +true+ if you are validating
|
50
|
+
# a database column, since the attribute is typecast from "1" to +true+
|
51
|
+
# before validation.
|
52
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
53
|
+
# if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
|
54
|
+
# or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
55
|
+
# method, proc or string should return or evaluate to a true or false
|
56
|
+
# value.
|
57
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
58
|
+
# determine if the validation should not occur (for example,
|
59
|
+
# <tt>:unless => :skip_validation</tt>, or
|
60
|
+
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
|
61
|
+
# The method, proc or string should return or evaluate to a true or
|
62
|
+
# false value.
|
27
63
|
def validates_acceptance_of(*attr_names)
|
28
|
-
|
29
|
-
configuration.update(attr_names.extract_options!)
|
30
|
-
|
31
|
-
db_cols = begin
|
32
|
-
column_names
|
33
|
-
rescue Exception # To ignore both statement and connection errors
|
34
|
-
[]
|
35
|
-
end
|
36
|
-
|
37
|
-
names = attr_names.reject { |name| db_cols.include?(name.to_s) }
|
38
|
-
attr_accessor(*names)
|
39
|
-
|
40
|
-
validates_each(attr_names,configuration) do |record, attr_name, value|
|
41
|
-
unless value == configuration[:accept]
|
42
|
-
record.errors.add(attr_name, :accepted, :default => configuration[:message])
|
43
|
-
end
|
44
|
-
end
|
64
|
+
validates_with AcceptanceValidator, _merge_attributes(attr_names)
|
45
65
|
end
|
46
66
|
end
|
47
67
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'active_support/callbacks'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
module Callbacks
|
6
|
+
# == Active Model Validation callbacks
|
7
|
+
#
|
8
|
+
# Provides an interface for any class to have <tt>before_validation</tt> and
|
9
|
+
# <tt>after_validation</tt> callbacks.
|
10
|
+
#
|
11
|
+
# First, extend ActiveModel::Callbacks from the class you are creating:
|
12
|
+
#
|
13
|
+
# class MyModel
|
14
|
+
# include ActiveModel::Validations::Callbacks
|
15
|
+
#
|
16
|
+
# before_validation :do_stuff_before_validation
|
17
|
+
# after_validation :do_tuff_after_validation
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Like other before_* callbacks if <tt>before_validation</tt> returns false
|
21
|
+
# then <tt>valid?</tt> will not be called.
|
22
|
+
extend ActiveSupport::Concern
|
23
|
+
|
24
|
+
included do
|
25
|
+
include ActiveSupport::Callbacks
|
26
|
+
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def before_validation(*args, &block)
|
31
|
+
options = args.last
|
32
|
+
if options.is_a?(Hash) && options[:on]
|
33
|
+
options[:if] = Array.wrap(options[:if])
|
34
|
+
options[:if] << "self.validation_context == :#{options[:on]}"
|
35
|
+
end
|
36
|
+
set_callback(:validation, :before, *args, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_validation(*args, &block)
|
40
|
+
options = args.extract_options!
|
41
|
+
options[:prepend] = true
|
42
|
+
options[:if] = Array.wrap(options[:if])
|
43
|
+
options[:if] << "!halted && value != false"
|
44
|
+
options[:if] << "self.validation_context == :#{options[:on]}" if options[:on]
|
45
|
+
set_callback(:validation, :after, *(args << options), &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# Overwrite run validations to include callbacks.
|
52
|
+
def run_validations!
|
53
|
+
_run_validation_callbacks { super }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|