validation_kit 1.0.5 → 2.0.1

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.
@@ -1,123 +1,145 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
4
  class PhoneValidator < ActiveModel::EachValidator
5
+ include CountryOption
6
+
7
+ # Digits right after a US/CA number with no marker in front of them (any
8
+ # letter, as in x, ext or extension, or #, # or №): a mistyped number like
9
+ # 212-555-12345, not an extension. \p{Nd} also catches non-ASCII digits.
10
+ UNMARKED_US_CA_EXTENSION = /\A[^[:alpha:]##№]*\p{Nd}/
11
+
12
+ # Australian states and territories (the area_key: values), and the
13
+ # landline area code each one adds.
14
+ AU_AREA_CODES = {
15
+ "NSW" => "02", "ACT" => "02", "VIC" => "03", "TAS" => "03",
16
+ "QLD" => "07", "SA" => "08", "NT" => "08", "WA" => "08"
17
+ }.freeze
18
+
19
+ # area_key: is a fixed state, so a typo fails when the model is loaded
20
+ # rather than silently adding the wrong area code.
21
+ def check_validity!
22
+ area_code_for_key(options[:area_key])
23
+ end
24
+
3
25
  def regex_for_country(country_code)
26
+ country_code = country_code.to_s.strip.upcase
27
+
4
28
  if country_code.blank?
5
29
  nil
6
- elsif ["AU"].include?(country_code)
7
- /(^(1300|1800|1900|1902)\d{6}$)|(^([0]?[1|2|3|7|8])?[1-9][0-9]{7}$)|(^13\d{4}$)|(^[0]?4\d{8}$)/
8
- elsif ["US", "CA"].include?(country_code)
9
- /^1?[2-9]\d{2}[2-9]\d{2}\d{4}/
10
- else
11
- nil
30
+ elsif country_code == "AU"
31
+ /\A(?:(?:1300|1800|1900|1902)\d{6}|(?:0?[12378])?[1-9][0-9]{7}|13\d{4}|0?4\d{8})\z/
32
+ elsif %w[US CA].include?(country_code)
33
+ /\A1?[2-9]\d{2}[2-9]\d{2}\d{4}/
12
34
  end
13
35
  end
14
36
 
15
37
  def validate_each(record, attribute, value)
16
- if options[:country].is_a?(String)
17
- country = options[:country]
18
- elsif options[:country].is_a?(Symbol) && record.respond_to?(options[:country])
19
- country = record.send(options[:country])
20
- elsif record.respond_to?(:country)
21
- country = record.send(:country)
22
- else
23
- country = false
24
- end
25
-
38
+ country = country_for(record)
26
39
  return unless country
40
+
41
+ # accept "us", :US, " US " as well as "US"
42
+ country = country.to_s.strip.upcase
43
+ return if country.empty?
44
+
27
45
  current_regex = regex_for_country(country)
28
46
  return unless current_regex
29
47
 
30
- new_value = value.to_s.gsub(/[^0-9]/, '')
31
- new_value ||= ''
32
-
33
- model_name = record.class.to_s
48
+ new_value = value.to_s.gsub(/[^0-9]/, "")
34
49
 
35
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.invalid",
36
- :default => [:"activerecord.errors.models.#{model_name.underscore}.invalid",
37
- options[:message], :'activerecord.errors.messages.invalid'])
50
+ # allow_blank/allow_nil are handled by ActiveModel on the original value,
51
+ # so input that only becomes blank once cleaned up (e.g. "n/a") is invalid.
52
+ valid = current_regex.match?(new_value)
53
+ # The US/CA regex only checks the start of the digits; format_as_phone is
54
+ # what rejects extra digits that aren't a marked extension.
55
+ valid &&= !format_as_phone(value, country).nil? if %w[US CA].include?(country)
38
56
 
39
- unless (options[:allow_blank] && new_value.blank?) || new_value =~ current_regex
40
- record.errors.add(attribute, message)
41
- else
57
+ if valid
42
58
  if options[:set]
43
59
  formatted_phone = format_as_phone(value, country, options[:area_key])
44
60
  if formatted_phone.nil?
45
- record.errors.add(attribute, message)
61
+ record.errors.add(attribute, :invalid, message: options[:message])
46
62
  else
47
- record.send(attribute.to_s + '=', formatted_phone)
63
+ record.public_send("#{attribute}=", formatted_phone)
48
64
  end
49
- end # options
50
- end # unless
65
+ end
66
+ else
67
+ record.errors.add(attribute, :invalid, message: options[:message])
68
+ end
51
69
  end
52
70
 
53
71
  def format_as_phone(arg, country_code = nil, area_key = nil)
54
- return nil if (arg.blank? or country_code.blank? or !regex_for_country(country_code))
72
+ # Checked first, so a bad key always raises, whatever number is passed.
73
+ area_code = area_code_for_key(area_key)
74
+ country_code = country_code.to_s.strip.upcase
75
+ return nil if arg.blank? || country_code.blank? || !regex_for_country(country_code)
55
76
 
56
- number = arg.gsub(/[^0-9]/, '')
77
+ arg = arg.to_s
78
+ number = arg.gsub(/[^0-9]/, "")
57
79
 
58
80
  if country_code == "AU"
59
- if number =~ /^(1300|1800|1900|1902)\d{6}$/
60
- number.insert(4, ' ').insert(8, ' ')
61
- elsif number =~ /^([0]?[1|2|3|7|8])?[1-9][0-9]{7}$/
62
- if number =~ /^[1-9][0-9]{7}$/
63
- number = number.insert(0, area_code_for_key(area_key))
64
- end
65
- number = number.insert(0, '0') if number =~ /^[1|2|3|7|8][1-9][0-9]{7}$/
66
-
67
- number.insert(0, '(').insert(3, ') ').insert(9, ' ')
68
- elsif number =~ /^13\d{4}$/
69
- number.insert(2, ' ').insert(5, ' ')
70
- elsif number =~ /^[0]?4\d{8}$/
71
- number = number.insert(0, '0') if number =~ /^4\d{8}$/
72
-
73
- number.insert(4, ' ').insert(8, ' ')
74
- else
75
- number
81
+ case number
82
+ when /\A(?:1300|1800|1900|1902)\d{6}\z/
83
+ number.insert(4, " ").insert(8, " ")
84
+ when /\A(?:0?[12378])?[1-9][0-9]{7}\z/
85
+ number.insert(0, area_code) if /\A[1-9][0-9]{7}\z/.match?(number)
86
+ number.insert(0, "0") if /\A[12378][1-9][0-9]{7}\z/.match?(number)
87
+
88
+ number.insert(0, "(").insert(3, ") ").insert(9, " ")
89
+ when /\A13\d{4}\z/
90
+ number.insert(2, " ").insert(5, " ")
91
+ when /\A0?4\d{8}\z/
92
+ number.insert(0, "0") if /\A4\d{8}\z/.match?(number)
93
+
94
+ number.insert(4, " ").insert(8, " ")
76
95
  end
77
- elsif ["CA", "US"].include?(country_code)
78
- digit_count = number.length
96
+ elsif %w[CA US].include?(country_code)
79
97
  # if it's too short
80
- if digit_count < 10
81
- return number
82
- end
98
+ return nil if number.length < 10
83
99
 
84
- # strip off any leading ones
85
- if number[0..0] == "1"
86
- number = number[1..10]
87
- end
100
+ # strip off the leading 1 (country code); any digits beyond ten are an
101
+ # extension, unless they're unmarked (UNMARKED_US_CA_EXTENSION)
102
+ leading_one = number.length > 10 && number.start_with?("1")
103
+ number = number[1..] if leading_one
88
104
 
89
105
  area_code = number[0..2]
90
106
  exchange = number[3..5]
91
107
  sln = number[6..9]
92
108
 
93
- if digit_count == 10
94
- extension = nil
95
- else
96
- # save everything after the SLN as extension
97
- sln_index = arg.index(sln)
98
- # if something went wrong, return nil so we can error out
99
- # i.e. 519 444 000 ext 123 would cause sln to be 0001, which is not found
100
- # in the original string
101
- return nil if sln_index.nil?
102
- extension = " %s" % arg[(sln_index+4)..-1].strip
109
+ # everything after the last digit of the number
110
+ national = arg[/\A(?:\D*\d){#{leading_one ? 11 : 10}}/]
111
+ rest = arg[national.length..]
112
+
113
+ # if letters appear among the number's digits, the extension's digits
114
+ # were counted as part of the number (e.g. 519 444 000 ext 123), so
115
+ # return nil to error out
116
+ return nil if number.length > 10 && national.sub(/\A\D*/, "").match?(/[[:alpha:]]/)
117
+
118
+ # Text after the number with no digits in it (e.g. "(cell)") is dropped;
119
+ # with digits, it's the extension, if they're marked as one.
120
+ extension = nil
121
+ if rest.match?(/\p{Nd}/)
122
+ return nil if UNMARKED_US_CA_EXTENSION.match?(rest)
123
+
124
+ # [[:space:]] also covers non-breaking spaces, which strip doesn't
125
+ extension = " #{rest.strip.sub(/\A[[:space:],;]+/, "").sub(/[[:space:]]+\z/, "")}"
103
126
  end
104
127
 
105
- "(%s) %s-%s%s" % [area_code, exchange, sln, extension]
128
+ "(#{area_code}) #{exchange}-#{sln}#{extension}"
106
129
  end
107
130
  end
108
131
 
132
+ # key is an AU state, in any case, as a string or symbol (always the state
133
+ # itself, never a method name); nil or blank means NSW/ACT. Anything else
134
+ # raises, rather than silently adding the NSW/ACT code (02) to, say, a
135
+ # Victorian number.
109
136
  def area_code_for_key(key)
110
- case key
111
- when 'NSW' then '02'
112
- when 'ACT' then '02'
113
- when 'VIC' then '03'
114
- when 'TAS' then '03'
115
- when 'QLD' then '07'
116
- when 'SA' then '08'
117
- when 'NT' then '08'
118
- when 'WA' then '08'
119
- else
120
- '02'
137
+ state = key.to_s.strip.upcase
138
+ return AU_AREA_CODES["NSW"] if state.empty?
139
+
140
+ AU_AREA_CODES.fetch(state) do
141
+ raise ArgumentError, "area_key: #{key.inspect} isn't an Australian state or territory " \
142
+ "(#{AU_AREA_CODES.keys.join(", ")})"
121
143
  end
122
144
  end
123
145
  end
@@ -1,88 +1,87 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
4
  class PostalCodeValidator < ActiveModel::EachValidator
5
+ include CountryOption
6
+
3
7
  def postal_code_regex_for_country(country_code)
8
+ country_code = country_code.to_s.strip.upcase
9
+
4
10
  if country_code.blank?
5
11
  nil
6
- elsif ["AU", "NZ"].include?(country_code)
7
- /\d{4}/
8
- elsif ["US"].include?(country_code)
9
- /\d{5}(-\d{4})?/
10
- elsif ["CA"].include?(country_code)
11
- /[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTWVXYZ]\d[ABCEGHJKLMNPRSTWVXYZ]\d/
12
- else
13
- nil
12
+ elsif %w[AU NZ].include?(country_code)
13
+ /\A\d{4}\z/
14
+ elsif country_code == "US"
15
+ /\A\d{5}(?:-?\d{4})?\z/
16
+ elsif country_code == "CA"
17
+ /\A[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTWVXYZ] ?\d[ABCEGHJKLMNPRSTWVXYZ]\d\z/
18
+ elsif %w[UK GB].include?(country_code)
19
+ /\A(?:[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0AA)\z/
14
20
  end
15
21
  end
16
22
 
17
23
  def disallowed_characters_for_country(country_code)
24
+ country_code = country_code.to_s.strip.upcase
25
+
18
26
  if country_code.blank?
19
27
  nil
20
- elsif ["US", "AU", "NZ"].include?(country_code)
28
+ elsif %w[US AU NZ].include?(country_code)
21
29
  /[^0-9]/
22
- elsif ["CA", "UK"].include?(country_code)
30
+ elsif %w[CA UK GB].include?(country_code)
23
31
  /[^0-9A-Z]/
24
- else
25
- nil
26
32
  end
27
33
  end
28
34
 
29
35
  def validate_each(record, attribute, value)
30
- if options[:country].is_a?(String)
31
- country = options[:country]
32
- elsif options[:country].is_a?(Symbol) and record.respond_to?(options[:country])
33
- country = record.send(options[:country])
34
- elsif record.respond_to?(:country)
35
- country = record.send(:country)
36
- else
37
- country = false
38
- end
39
-
36
+ country = country_for(record)
40
37
  return unless country
38
+
39
+ # accept "us", :US, " US " as well as "US"
40
+ country = country.to_s.strip.upcase
41
+ return if country.empty?
42
+
41
43
  current_regex = postal_code_regex_for_country(country)
42
44
  return unless current_regex
43
- disallowed_characters = disallowed_characters_for_country(country)
44
45
 
45
- new_value = value.nil? ? "" : value.upcase.gsub(disallowed_characters, '')
46
+ disallowed_characters = disallowed_characters_for_country(country)
46
47
 
47
- model_name = record.class.to_s
48
+ new_value = value.to_s.upcase.gsub(disallowed_characters, "")
48
49
 
49
- unless (options[:allow_blank] && new_value.blank?) || new_value =~ current_regex
50
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.invalid",
51
- :default => [:"activerecord.errors.models.#{model_name.underscore}.invalid",
52
- options[:message],
53
- :'activerecord.errors.messages.invalid'])
54
- record.errors.add(attribute, message)
50
+ # allow_blank/allow_nil are handled by ActiveModel on the original value,
51
+ # so input that only becomes blank once cleaned up (e.g. "n/a") is invalid.
52
+ if current_regex.match?(new_value)
53
+ if options[:set]
54
+ record.public_send("#{attribute}=", format_as_postal_code(new_value, country, disallowed_characters))
55
+ end
55
56
  else
56
- record.send(attribute.to_s + '=',
57
- format_as_postal_code(new_value, country, disallowed_characters)
58
- ) if options[:set]
57
+ record.errors.add(attribute, :invalid, message: options[:message])
59
58
  end
60
59
  end
61
60
 
62
61
  def format_as_postal_code(arg, country_code, disallowed_characters)
63
- return nil if (arg.blank? or country_code.blank? or !postal_code_regex_for_country(country_code))
62
+ country_code = country_code.to_s.strip.upcase
63
+ return nil if arg.blank? || country_code.blank? || !postal_code_regex_for_country(country_code)
64
64
 
65
- postal_code = arg.gsub(disallowed_characters, '')
65
+ postal_code = arg.to_s.gsub(disallowed_characters, "")
66
66
 
67
- if ["US"].include?(country_code)
67
+ if country_code == "US"
68
68
  digit_count = postal_code.length
69
69
  if digit_count == 5
70
- return postal_code
70
+ postal_code
71
71
  elsif digit_count == 9
72
- return "%s-%s" % [postal_code[0..4], postal_code[5..8]]
73
- else
74
- return nil
72
+ "#{postal_code[0..4]}-#{postal_code[5..8]}"
75
73
  end
76
74
 
77
- elsif ["AU", "NZ"].include?(country_code)
75
+ elsif %w[AU NZ].include?(country_code)
78
76
  postal_code
79
77
 
80
- elsif ["CA"].include?(country_code)
81
- fsa = postal_code[0..2]
82
- lda = postal_code[3..5]
78
+ elsif country_code == "CA"
79
+ # forward sortation area, then local delivery unit
80
+ "#{postal_code[0..2]} #{postal_code[3..5]}"
83
81
 
84
- postal_code = "%s %s" % [fsa, lda]
85
- postal_code.upcase
82
+ elsif %w[UK GB].include?(country_code)
83
+ # the inward code is always the last three characters
84
+ "#{postal_code[0...-3]} #{postal_code[-3..]}"
86
85
  end
87
86
  end
88
87
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
- VERSION = "1.0.5"
4
+ VERSION = "2.0.1"
3
5
  end
@@ -1,10 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+ require "active_support/core_ext/string/inflections"
1
5
  require "validation_kit/version"
6
+ require "validation_kit/country_option"
7
+
8
+ module ValidationKit
9
+ VALIDATORS = {} # rubocop:disable Style/MutableConstant -- filled below, then frozen
10
+
11
+ # Lets `validates :email, email: true` (and phone:, postal_code:,
12
+ # mixed_case:) find this gem's validators. Rails resolves those keys with
13
+ # const_get on the model, and Ruby only calls const_missing once normal
14
+ # lookup -- including autoloading an app's own app/validators/*.rb -- has
15
+ # failed, so an app's validator of the same name always wins.
16
+ module ValidatorLookup
17
+ def const_missing(name)
18
+ VALIDATORS.fetch(name) { super }
19
+ end
20
+ end
21
+ end
2
22
 
3
23
  lib_path = File.dirname(__FILE__)
4
- validators = Dir[File.join(lib_path, '**', '*_validator.rb')]
5
- validators.each do |v|
6
- require v
7
- validator_class = File.basename(v, '.rb').camelize
8
- validator = "ValidationKit::#{validator_class}".constantize
9
- ActiveModel::Validations.const_set(validator_class, validator)
24
+ Dir[File.join(lib_path, "**", "*_validator.rb")].each do |path|
25
+ require path
26
+ name = File.basename(path, ".rb").camelize
27
+ ValidationKit::VALIDATORS[name.to_sym] = ValidationKit.const_get(name)
10
28
  end
29
+ ValidationKit::VALIDATORS.freeze
30
+
31
+ ActiveModel::Validations::ClassMethods.include(ValidationKit::ValidatorLookup)
32
+
33
+ # Put the bundled translations first in the load path so an app's own
34
+ # locale files (which Rails appends later) can override them.
35
+ I18n.load_path.unshift(*Dir[File.join(lib_path, "validation_kit", "**", "locales", "*.yml")])
metadata CHANGED
@@ -1,16 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validation_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wes Morgan
8
8
  - Paul Schreiber
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2018-02-19 00:00:00.000000000 Z
13
- dependencies: []
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.2'
14
27
  description: A collection of various validators for Rails forms
15
28
  email:
16
29
  - wes@turbovote.org
@@ -19,26 +32,26 @@ executables: []
19
32
  extensions: []
20
33
  extra_rdoc_files: []
21
34
  files:
22
- - ".gitignore"
23
- - Gemfile
24
- - Rakefile
35
+ - CHANGELOG.md
36
+ - LICENSE
37
+ - README.md
25
38
  - lib/validation_kit.rb
26
- - lib/validation_kit/email_validator/README
39
+ - lib/validation_kit/country_option.rb
27
40
  - lib/validation_kit/email_validator/email_validator.rb
28
- - lib/validation_kit/mixed_case_validator/README
29
41
  - lib/validation_kit/mixed_case_validator/config/locales/en.yml
30
42
  - lib/validation_kit/mixed_case_validator/config/locales/fr.yml
31
43
  - lib/validation_kit/mixed_case_validator/mixed_case_validator.rb
32
- - lib/validation_kit/phone_validator/README
33
44
  - lib/validation_kit/phone_validator/phone_validator.rb
34
- - lib/validation_kit/postal_code_validator/README
35
45
  - lib/validation_kit/postal_code_validator/postal_code_validator.rb
36
46
  - lib/validation_kit/version.rb
37
- - validation_kit.gemspec
38
- homepage: https://github.com/turbovote/validation_kit
39
- licenses: []
40
- metadata: {}
41
- post_install_message:
47
+ homepage: https://github.com/paulschreiber/validation_kit
48
+ licenses:
49
+ - MIT
50
+ metadata:
51
+ rubygems_mfa_required: 'true'
52
+ source_code_uri: https://github.com/paulschreiber/validation_kit
53
+ bug_tracker_uri: https://github.com/paulschreiber/validation_kit/issues
54
+ changelog_uri: https://github.com/paulschreiber/validation_kit/blob/main/CHANGELOG.md
42
55
  rdoc_options: []
43
56
  require_paths:
44
57
  - lib
@@ -46,16 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
59
  requirements:
47
60
  - - ">="
48
61
  - !ruby/object:Gem::Version
49
- version: '0'
62
+ version: '3.4'
50
63
  required_rubygems_version: !ruby/object:Gem::Requirement
51
64
  requirements:
52
65
  - - ">="
53
66
  - !ruby/object:Gem::Version
54
67
  version: '0'
55
68
  requirements: []
56
- rubyforge_project: validation_kit
57
- rubygems_version: 2.7.3
58
- signing_key:
69
+ rubygems_version: 4.0.10
59
70
  specification_version: 4
60
71
  summary: Handy validations for Rails forms
61
72
  test_files: []
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in validation_kit.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"
@@ -1,32 +0,0 @@
1
- validates_as_email
2
- ==================
3
-
4
- Validation module for email addresses.
5
-
6
- Installation
7
- ============
8
-
9
- You can install the plugin the traditional way. Go to your application root
10
- and do:
11
-
12
- script/plugin install git://github.com/paulschreiber/validates_as_email.git
13
-
14
- Example
15
- =======
16
-
17
- class Person < ActiveRecord::Base
18
- validates_as_email :email
19
- end
20
-
21
- p = Person.new(:email => "Bob")
22
- p.valid? # false
23
-
24
- p = Person.new(:email => "joe@foobar.com")
25
- p.valid? # true
26
-
27
- Just like with built-in ActiveRecord validations, you can optionally supply a :message parameter with a custom error. Or, you can use Rails' built-in localization system and
28
-
29
-
30
- = License
31
-
32
- Copyright (c) 2010 Paul Schreiber, released under the MIT license
@@ -1,59 +0,0 @@
1
- Validates Mixed Case Of
2
- =======================
3
-
4
- When validating a string item, ensure it is not all in capital or lowercase letters.
5
-
6
- Example
7
- =======
8
-
9
- class Person < ActiveRecord::Base
10
- validates_mixed_case_of :firstname
11
- end
12
-
13
- p = Person.new(:firstname => "BOB")
14
- p.valid? # false
15
- p = Person.new(:firstname => "Bob")
16
- p.valid? # true
17
-
18
- Attribute Names
19
- ===============
20
- Attribute names are looked up using Rails' I18n system. Create a hierarchy like so:
21
-
22
- en:
23
- activerecord:
24
- models:
25
- attributes:
26
- person:
27
- firstname: "first name"
28
-
29
- Alternately, pass in the :attribute_name option:
30
-
31
- class Person < ActiveRecord::Base
32
- validates_mixed_case_of :firstname, :attribute_name => "first name"
33
- end
34
-
35
-
36
- Error Messages
37
- ==============
38
- Error messages follow the standard ActiveRecord lookup method.
39
-
40
- You'll likely error messages can be customized like so:
41
-
42
- en:
43
- activerecord:
44
- errors:
45
- models:
46
- attributes:
47
- person:
48
- firstname:
49
- all_caps: "first name should not be in all caps"
50
-
51
- Alternatively, pass in tje :all_caps option:
52
-
53
- class Person < ActiveRecord::Base
54
- validates_mixed_case_of :firstname, :all_caps => "don't shout at me, bro"
55
- end
56
-
57
-
58
-
59
- Copyright 2011 Paul Schreiber, released under the MIT license