activemodel 3.2.22.5 → 4.0.0.beta1

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +85 -64
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +61 -24
  5. data/lib/active_model.rb +21 -11
  6. data/lib/active_model/attribute_methods.rb +150 -125
  7. data/lib/active_model/callbacks.rb +49 -34
  8. data/lib/active_model/conversion.rb +39 -19
  9. data/lib/active_model/deprecated_mass_assignment_security.rb +21 -0
  10. data/lib/active_model/dirty.rb +48 -32
  11. data/lib/active_model/errors.rb +176 -88
  12. data/lib/active_model/forbidden_attributes_protection.rb +27 -0
  13. data/lib/active_model/lint.rb +42 -55
  14. data/lib/active_model/locale/en.yml +3 -1
  15. data/lib/active_model/model.rb +97 -0
  16. data/lib/active_model/naming.rb +191 -51
  17. data/lib/active_model/railtie.rb +11 -1
  18. data/lib/active_model/secure_password.rb +55 -25
  19. data/lib/active_model/serialization.rb +51 -27
  20. data/lib/active_model/serializers/json.rb +83 -46
  21. data/lib/active_model/serializers/xml.rb +46 -12
  22. data/lib/active_model/test_case.rb +0 -12
  23. data/lib/active_model/translation.rb +9 -10
  24. data/lib/active_model/validations.rb +154 -52
  25. data/lib/active_model/validations/absence.rb +31 -0
  26. data/lib/active_model/validations/acceptance.rb +10 -22
  27. data/lib/active_model/validations/callbacks.rb +78 -25
  28. data/lib/active_model/validations/clusivity.rb +41 -0
  29. data/lib/active_model/validations/confirmation.rb +13 -23
  30. data/lib/active_model/validations/exclusion.rb +26 -55
  31. data/lib/active_model/validations/format.rb +44 -34
  32. data/lib/active_model/validations/inclusion.rb +22 -52
  33. data/lib/active_model/validations/length.rb +48 -49
  34. data/lib/active_model/validations/numericality.rb +30 -32
  35. data/lib/active_model/validations/presence.rb +12 -22
  36. data/lib/active_model/validations/validates.rb +68 -36
  37. data/lib/active_model/validations/with.rb +28 -23
  38. data/lib/active_model/validator.rb +22 -22
  39. data/lib/active_model/version.rb +4 -4
  40. metadata +23 -24
  41. data/lib/active_model/mass_assignment_security.rb +0 -237
  42. data/lib/active_model/mass_assignment_security/permission_set.rb +0 -40
  43. data/lib/active_model/mass_assignment_security/sanitizer.rb +0 -59
  44. data/lib/active_model/observer_array.rb +0 -147
  45. data/lib/active_model/observing.rb +0 -252
@@ -0,0 +1,31 @@
1
+ module ActiveModel
2
+ module Validations
3
+ # == Active Model Absence Validator
4
+ class AbsenceValidator < EachValidator #:nodoc:
5
+ def validate_each(record, attr_name, value)
6
+ record.errors.add(attr_name, :present, options) if value.present?
7
+ end
8
+ end
9
+
10
+ module HelperMethods
11
+ # Validates that the specified attributes are blank (as defined by
12
+ # Object#blank?). Happens by default on save.
13
+ #
14
+ # class Person < ActiveRecord::Base
15
+ # validates_absence_of :first_name
16
+ # end
17
+ #
18
+ # The first_name attribute must be in the object and it must be blank.
19
+ #
20
+ # Configuration options:
21
+ # * <tt>:message</tt> - A custom error message (default is: "must be blank").
22
+ #
23
+ # There is also a list of default options supported by every validator:
24
+ # +:if+, +:unless+, +:on+ and +:strict+.
25
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
26
+ def validates_absence_of(*attr_names)
27
+ validates_with AbsenceValidator, _merge_attributes(attr_names)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,9 +1,9 @@
1
1
  module ActiveModel
2
- # == Active Model Acceptance Validator
2
+
3
3
  module Validations
4
- class AcceptanceValidator < EachValidator
4
+ class AcceptanceValidator < EachValidator # :nodoc:
5
5
  def initialize(options)
6
- super(options.reverse_merge(:allow_nil => true, :accept => "1"))
6
+ super({ :allow_nil => true, :accept => "1" }.merge!(options))
7
7
  end
8
8
 
9
9
  def validate_each(record, attribute, value)
@@ -22,11 +22,11 @@ module ActiveModel
22
22
 
23
23
  module HelperMethods
24
24
  # Encapsulates the pattern of wanting to validate the acceptance of a
25
- # terms of service check box (or similar agreement). Example:
25
+ # terms of service check box (or similar agreement).
26
26
  #
27
27
  # class Person < ActiveRecord::Base
28
28
  # validates_acceptance_of :terms_of_service
29
- # validates_acceptance_of :eula, :message => "must be abided"
29
+ # validates_acceptance_of :eula, message: 'must be abided'
30
30
  # end
31
31
  #
32
32
  # If the database column does not exist, the +terms_of_service+ attribute
@@ -36,29 +36,17 @@ module ActiveModel
36
36
  # Configuration options:
37
37
  # * <tt>:message</tt> - A custom error message (default is: "must be
38
38
  # accepted").
39
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
40
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
41
- # and <tt>:update</tt>.
42
39
  # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default
43
- # is true).
40
+ # is +true+).
44
41
  # * <tt>:accept</tt> - Specifies value that is considered accepted.
45
42
  # The default value is a string "1", which makes it easy to relate to
46
43
  # an HTML checkbox. This should be set to +true+ if you are validating
47
44
  # a database column, since the attribute is typecast from "1" to +true+
48
45
  # before validation.
49
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
50
- # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
51
- # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
52
- # method, proc or string should return or evaluate to a true or false
53
- # value.
54
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to
55
- # determine if the validation should not occur (for example,
56
- # <tt>:unless => :skip_validation</tt>, or
57
- # <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
58
- # The method, proc or string should return or evaluate to a true or
59
- # false value.
60
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
61
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
46
+ #
47
+ # There is also a list of default options supported by every validator:
48
+ # +:if+, +:unless+, +:on+ and +:strict+.
49
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
62
50
  def validates_acceptance_of(*attr_names)
63
51
  validates_with AcceptanceValidator, _merge_attributes(attr_names)
64
52
  end
@@ -1,47 +1,100 @@
1
- require 'active_support/callbacks'
2
-
3
1
  module ActiveModel
4
2
  module Validations
3
+ # == Active \Model Validation Callbacks
4
+ #
5
+ # Provides an interface for any class to have +before_validation+ and
6
+ # +after_validation+ callbacks.
7
+ #
8
+ # First, include ActiveModel::Validations::Callbacks from the class you are
9
+ # creating:
10
+ #
11
+ # class MyModel
12
+ # include ActiveModel::Validations::Callbacks
13
+ #
14
+ # before_validation :do_stuff_before_validation
15
+ # after_validation :do_stuff_after_validation
16
+ # end
17
+ #
18
+ # Like other <tt>before_*</tt> callbacks if +before_validation+ returns
19
+ # +false+ then <tt>valid?</tt> will not be called.
5
20
  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_stuff_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
21
  extend ActiveSupport::Concern
23
22
 
24
23
  included do
25
24
  include ActiveSupport::Callbacks
26
- define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
25
+ define_callbacks :validation, :terminator => "result == false", :skip_after_callbacks_if_terminated => true, :scope => [:kind, :name]
27
26
  end
28
27
 
29
28
  module ClassMethods
29
+ # Defines a callback that will get called right before validation
30
+ # happens.
31
+ #
32
+ # class Person
33
+ # include ActiveModel::Validations
34
+ # include ActiveModel::Validations::Callbacks
35
+ #
36
+ # attr_accessor :name
37
+ #
38
+ # validates_length_of :name, maximum: 6
39
+ #
40
+ # before_validation :remove_whitespaces
41
+ #
42
+ # private
43
+ #
44
+ # def remove_whitespaces
45
+ # name.strip!
46
+ # end
47
+ # end
48
+ #
49
+ # person = Person.new
50
+ # person.name = ' bob '
51
+ # person.valid? # => true
52
+ # person.name # => "bob"
30
53
  def before_validation(*args, &block)
31
54
  options = args.last
32
55
  if options.is_a?(Hash) && options[:on]
33
- options[:if] = Array.wrap(options[:if])
34
- options[:if].unshift("self.validation_context == :#{options[:on]}")
56
+ options[:if] = Array(options[:if])
57
+ options[:on] = Array(options[:on])
58
+ options[:if].unshift("#{options[:on]}.include? self.validation_context")
35
59
  end
36
60
  set_callback(:validation, :before, *args, &block)
37
61
  end
38
62
 
63
+ # Defines a callback that will get called right after validation
64
+ # happens.
65
+ #
66
+ # class Person
67
+ # include ActiveModel::Validations
68
+ # include ActiveModel::Validations::Callbacks
69
+ #
70
+ # attr_accessor :name, :status
71
+ #
72
+ # validates_presence_of :name
73
+ #
74
+ # after_validation :set_status
75
+ #
76
+ # private
77
+ #
78
+ # def set_status
79
+ # self.status = errors.empty?
80
+ # end
81
+ # end
82
+ #
83
+ # person = Person.new
84
+ # person.name = ''
85
+ # person.valid? # => false
86
+ # person.status # => false
87
+ # person.name = 'bob'
88
+ # person.valid? # => true
89
+ # person.status # => true
39
90
  def after_validation(*args, &block)
40
91
  options = args.extract_options!
41
92
  options[:prepend] = true
42
- options[:if] = Array.wrap(options[:if])
43
- options[:if] << "!halted"
44
- options[:if].unshift("self.validation_context == :#{options[:on]}") if options[:on]
93
+ options[:if] = Array(options[:if])
94
+ if options[:on]
95
+ options[:on] = Array(options[:on])
96
+ options[:if].unshift("#{options[:on]}.include? self.validation_context")
97
+ end
45
98
  set_callback(:validation, :after, *(args << options), &block)
46
99
  end
47
100
  end
@@ -49,7 +102,7 @@ module ActiveModel
49
102
  protected
50
103
 
51
104
  # Overwrite run validations to include callbacks.
52
- def run_validations!
105
+ def run_validations! #:nodoc:
53
106
  run_callbacks(:validation) { super }
54
107
  end
55
108
  end
@@ -0,0 +1,41 @@
1
+ require 'active_support/core_ext/range'
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ module Clusivity #:nodoc:
6
+ ERROR_MESSAGE = "An object with the method #include? or a proc, lambda or symbol is required, " \
7
+ "and must be supplied as the :in (or :within) option of the configuration hash"
8
+
9
+ def check_validity!
10
+ unless delimiter.respond_to?(:include?) || delimiter.respond_to?(:call) || delimiter.respond_to?(:to_sym)
11
+ raise ArgumentError, ERROR_MESSAGE
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def include?(record, value)
18
+ exclusions = if delimiter.respond_to?(:call)
19
+ delimiter.call(record)
20
+ elsif delimiter.respond_to?(:to_sym)
21
+ record.send(delimiter)
22
+ else
23
+ delimiter
24
+ end
25
+
26
+ exclusions.send(inclusion_method(exclusions), value)
27
+ end
28
+
29
+ def delimiter
30
+ @delimiter ||= options[:in] || options[:within]
31
+ end
32
+
33
+ # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
34
+ # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
35
+ # uses the previous logic of comparing a value with the range endpoints.
36
+ def inclusion_method(enumerable)
37
+ enumerable.is_a?(Range) ? :cover? : :include?
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,10 +1,11 @@
1
1
  module ActiveModel
2
- # == Active Model Confirmation Validator
2
+
3
3
  module Validations
4
- class ConfirmationValidator < EachValidator
4
+ class ConfirmationValidator < EachValidator # :nodoc:
5
5
  def validate_each(record, attribute, value)
6
6
  if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
7
- record.errors.add(attribute, :confirmation, options)
7
+ human_attribute_name = record.class.human_attribute_name(attribute)
8
+ record.errors.add(:"#{attribute}_confirmation", :confirmation, options.merge(:attribute => human_attribute_name))
8
9
  end
9
10
  end
10
11
 
@@ -17,13 +18,13 @@ module ActiveModel
17
18
 
18
19
  module HelperMethods
19
20
  # Encapsulates the pattern of wanting to validate a password or email
20
- # address field with a confirmation. For example:
21
+ # address field with a confirmation.
21
22
  #
22
23
  # Model:
23
24
  # class Person < ActiveRecord::Base
24
25
  # validates_confirmation_of :user_name, :password
25
26
  # validates_confirmation_of :email_address,
26
- # :message => "should match confirmation"
27
+ # message: 'should match confirmation'
27
28
  # end
28
29
  #
29
30
  # View:
@@ -36,29 +37,18 @@ module ActiveModel
36
37
  # attribute.
37
38
  #
38
39
  # NOTE: This check is performed only if +password_confirmation+ is not
39
- # +nil+, and by default only on save. To require confirmation, make sure
40
- # to add a presence check for the confirmation attribute:
40
+ # +nil+. To require confirmation, make sure to add a presence check for
41
+ # the confirmation attribute:
41
42
  #
42
- # validates_presence_of :password_confirmation, :if => :password_changed?
43
+ # validates_presence_of :password_confirmation, if: :password_changed?
43
44
  #
44
45
  # Configuration options:
45
46
  # * <tt>:message</tt> - A custom error message (default is: "doesn't match
46
47
  # confirmation").
47
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
48
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
49
- # and <tt>:update</tt>.
50
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
51
- # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
52
- # or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
53
- # method, proc or string should return or evaluate to a true or false
54
- # value.
55
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to
56
- # determine if the validation should not occur (e.g.
57
- # <tt>:unless => :skip_validation</tt>, or
58
- # <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
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
61
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
48
+ #
49
+ # There is also a list of default options supported by every validator:
50
+ # +:if+, +:unless+, +:on+ and +:strict+.
51
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
62
52
  def validates_confirmation_of(*attr_names)
63
53
  validates_with ConfirmationValidator, _merge_attributes(attr_names)
64
54
  end
@@ -1,76 +1,47 @@
1
- require 'active_support/core_ext/range'
1
+ require "active_model/validations/clusivity"
2
2
 
3
3
  module ActiveModel
4
- # == Active Model Exclusion Validator
5
- module Validations
6
- class ExclusionValidator < EachValidator
7
- ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
8
- "and must be supplied as the :in (or :within) option of the configuration hash"
9
4
 
10
- def check_validity!
11
- unless [:include?, :call].any? { |method| delimiter.respond_to?(method) }
12
- raise ArgumentError, ERROR_MESSAGE
13
- end
14
- end
5
+ module Validations
6
+ class ExclusionValidator < EachValidator # :nodoc:
7
+ include Clusivity
15
8
 
16
9
  def validate_each(record, attribute, value)
17
- exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
18
- if exclusions.send(inclusion_method(exclusions), value)
10
+ if include?(record, value)
19
11
  record.errors.add(attribute, :exclusion, options.except(:in, :within).merge!(:value => value))
20
12
  end
21
13
  end
22
-
23
- private
24
-
25
- def delimiter
26
- @delimiter ||= options[:in] || options[:within]
27
- end
28
-
29
- # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible
30
- # values in the range for equality, so it may be slow for large ranges. The new
31
- # <tt>Range#cover?</tt> uses the previous logic of comparing a value with the
32
- # range endpoints.
33
- def inclusion_method(enumerable)
34
- enumerable.is_a?(Range) ? :cover? : :include?
35
- end
36
14
  end
37
15
 
38
16
  module HelperMethods
39
- # Validates that the value of the specified attribute is not in a particular
40
- # enumerable object.
17
+ # Validates that the value of the specified attribute is not in a
18
+ # particular enumerable object.
41
19
  #
42
20
  # class Person < ActiveRecord::Base
43
- # validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
44
- # validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
45
- # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
46
- # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] },
47
- # :message => "should not be the same as your username or first name"
21
+ # validates_exclusion_of :username, in: %w( admin superuser ), message: "You don't belong here"
22
+ # validates_exclusion_of :age, in: 30..60, message: 'This site is only for under 30 and over 60'
23
+ # validates_exclusion_of :format, in: %w( mov avi ), message: "extension %{value} is not allowed"
24
+ # validates_exclusion_of :password, in: ->(person) { [person.username, person.first_name] },
25
+ # message: 'should not be the same as your username or first name'
26
+ # validates_exclusion_of :karma, in: :reserved_karmas
48
27
  # end
49
28
  #
50
29
  # Configuration options:
51
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be
52
- # part of. This can be supplied as a proc or lambda which returns an enumerable.
53
- # If the enumerable is a range the test is performed with <tt>Range#cover?</tt>
54
- # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
30
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't
31
+ # be part of. This can be supplied as a proc, lambda or symbol which returns an
32
+ # enumerable. If the enumerable is a range the test is performed with
55
33
  # * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
56
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
57
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
58
- # is +nil+ (default is +false+).
34
+ # <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
35
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
36
+ # reserved").
37
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the
38
+ # attribute is +nil+ (default is +false+).
59
39
  # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
60
- # attribute is blank (default is +false+).
61
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
62
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
63
- # and <tt>:update</tt>.
64
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the
65
- # validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
66
- # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
67
- # or string should return or evaluate to a true or false value.
68
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if
69
- # the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
70
- # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
71
- # proc or string should return or evaluate to a true or false value.
72
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
73
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
40
+ # attribute is blank(default is +false+).
41
+ #
42
+ # There is also a list of default options supported by every validator:
43
+ # +:if+, +:unless+, +:on+ and +:strict+.
44
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
74
45
  def validates_exclusion_of(*attr_names)
75
46
  validates_with ExclusionValidator, _merge_attributes(attr_names)
76
47
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveModel
2
- # == Active Model Format Validator
2
+
3
3
  module Validations
4
- class FormatValidator < EachValidator
4
+ class FormatValidator < EachValidator # :nodoc:
5
5
  def validate_each(record, attribute, value)
6
6
  if options[:with]
7
7
  regexp = option_call(record, :with)
@@ -32,28 +32,38 @@ module ActiveModel
32
32
  record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value))
33
33
  end
34
34
 
35
+ def regexp_using_multiline_anchors?(regexp)
36
+ regexp.source.start_with?("^") ||
37
+ (regexp.source.end_with?("$") && !regexp.source.end_with?("\\$"))
38
+ end
39
+
35
40
  def check_options_validity(options, name)
36
41
  option = options[name]
37
42
  if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
38
43
  raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
44
+ elsif option && option.is_a?(Regexp) &&
45
+ regexp_using_multiline_anchors?(option) && options[:multiline] != true
46
+ raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
47
+ "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
48
+ ":multiline => true option?"
39
49
  end
40
50
  end
41
51
  end
42
52
 
43
53
  module HelperMethods
44
- # Validates whether the value of the specified attribute is of the correct form,
45
- # going by the regular expression provided. You can require that the attribute
46
- # matches the regular expression:
54
+ # Validates whether the value of the specified attribute is of the correct
55
+ # form, going by the regular expression provided.You can require that the
56
+ # attribute matches the regular expression:
47
57
  #
48
58
  # class Person < ActiveRecord::Base
49
- # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
59
+ # validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
50
60
  # end
51
61
  #
52
- # Alternatively, you can require that the specified attribute does _not_ match
53
- # the regular expression:
62
+ # Alternatively, you can require that the specified attribute does _not_
63
+ # match the regular expression:
54
64
  #
55
65
  # class Person < ActiveRecord::Base
56
- # validates_format_of :email, :without => /NOSPAM/
66
+ # validates_format_of :email, without: /NOSPAM/
57
67
  # end
58
68
  #
59
69
  # You can also provide a proc or lambda which will determine the regular
@@ -62,41 +72,41 @@ module ActiveModel
62
72
  # class Person < ActiveRecord::Base
63
73
  # # Admin can have number as a first letter in their screen name
64
74
  # validates_format_of :screen_name,
65
- # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
75
+ # with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
66
76
  # end
67
77
  #
68
- # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string,
69
- # <tt>^</tt> and <tt>$</tt> match the start/end of a line.
78
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
79
+ # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
70
80
  #
71
- # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In
72
- # addition, both must be a regular expression or a proc or lambda, or else an
73
- # exception will be raised.
81
+ # Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
82
+ # the <tt>multiline: true</tt> option in case you use any of these two
83
+ # anchors in the provided regular expression. In most cases, you should be
84
+ # using <tt>\A</tt> and <tt>\z</tt>.
85
+ #
86
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
87
+ # In addition, both must be a regular expression or a proc or lambda, or
88
+ # else an exception will be raised.
74
89
  #
75
90
  # Configuration options:
76
91
  # * <tt>:message</tt> - A custom error message (default is: "is invalid").
77
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
78
- # is +nil+ (default is +false+).
92
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the
93
+ # attribute is +nil+ (default is +false+).
79
94
  # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
80
95
  # attribute is blank (default is +false+).
81
96
  # * <tt>:with</tt> - Regular expression that if the attribute matches will
82
- # result in a successful validation. This can be provided as a proc or lambda
83
- # returning regular expression which will be called at runtime.
84
- # * <tt>:without</tt> - Regular expression that if the attribute does not match
85
- # will result in a successful validation. This can be provided as a proc or
97
+ # result in a successful validation. This can be provided as a proc or
86
98
  # lambda returning regular expression which will be called at runtime.
87
- # * <tt>:on</tt> - Specifies when this validation is active. Runs in all
88
- # validation contexts by default (+nil+), other options are <tt>:create</tt>
89
- # and <tt>:update</tt>.
90
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the
91
- # validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
92
- # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
93
- # or string should return or evaluate to a true or false value.
94
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if
95
- # the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
96
- # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
97
- # proc or string should return or evaluate to a true or false value.
98
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
99
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
99
+ # * <tt>:without</tt> - Regular expression that if the attribute does not
100
+ # match will result in a successful validation. This can be provided as
101
+ # a proc or lambda returning regular expression which will be called at
102
+ # runtime.
103
+ # * <tt>:multiline</tt> - Set to true if your regular expression contains
104
+ # anchors that match the beginning or end of lines as opposed to the
105
+ # beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
106
+ #
107
+ # There is also a list of default options supported by every validator:
108
+ # +:if+, +:unless+, +:on+ and +:strict+.
109
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
100
110
  def validates_format_of(*attr_names)
101
111
  validates_with FormatValidator, _merge_attributes(attr_names)
102
112
  end