aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/lib/active_model')
-rw-r--r--activemodel/lib/active_model/naming.rb4
-rw-r--r--activemodel/lib/active_model/translation.rb18
-rw-r--r--activemodel/lib/active_model/validations/length.rb24
3 files changed, 34 insertions, 12 deletions
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index 953d24a3b2..3caa61e41b 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -71,8 +71,8 @@ module ActiveModel
# BookCover.model_name # => "BookCover"
# BookCover.model_name.human # => "Book cover"
#
- # BookCover.model_name.i18n_key # => "book_cover"
- # BookModule::BookCover.model_name.i18n_key # => "book_module.book_cover"
+ # BookCover.model_name.i18n_key # => :book_cover
+ # BookModule::BookCover.model_name.i18n_key # => :"book_module/book_cover"
#
# Providing the functionality that ActiveModel::Naming provides in your object
# is required to pass the Active Model Lint test. So either extending the provided
diff --git a/activemodel/lib/active_model/translation.rb b/activemodel/lib/active_model/translation.rb
index 6d64c81b5f..02b7c54d61 100644
--- a/activemodel/lib/active_model/translation.rb
+++ b/activemodel/lib/active_model/translation.rb
@@ -43,13 +43,25 @@ module ActiveModel
#
# Specify +options+ with additional translating options.
def human_attribute_name(attribute, options = {})
- defaults = lookup_ancestors.map do |klass|
- :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}"
+ defaults = []
+ parts = attribute.to_s.split(".", 2)
+ attribute = parts.pop
+ namespace = parts.pop
+
+ if namespace
+ lookup_ancestors.each do |klass|
+ defaults << :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}"
+ end
+ defaults << :"#{self.i18n_scope}.attributes.#{namespace}.#{attribute}"
+ else
+ lookup_ancestors.each do |klass|
+ defaults << :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}"
+ end
end
defaults << :"attributes.#{attribute}"
defaults << options.delete(:default) if options[:default]
- defaults << attribute.to_s.humanize
+ defaults << attribute.humanize
options.reverse_merge! :count => 1, :default => defaults
I18n.translate(defaults.shift, options)
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 6bc928bab7..a38de27b3c 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -1,3 +1,5 @@
+require "active_support/core_ext/string/encoding"
+
module ActiveModel
# == Active Model Length Validator
@@ -6,7 +8,6 @@ module ActiveModel
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
- DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]
def initialize(options)
@@ -36,14 +37,11 @@ module ActiveModel
end
def validate_each(record, attribute, value)
- value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String)
+ value = tokenize(value)
+ value_length = value.respond_to?(:length) ? value.length : value.to_s.length
CHECKS.each do |key, validity_check|
next unless check_value = options[key]
-
- value ||= [] if key == :maximum
-
- value_length = value.respond_to?(:length) ? value.length : value.to_s.length
next if value_length.send(validity_check, check_value)
errors_options = options.except(*RESERVED_OPTIONS)
@@ -55,6 +53,18 @@ module ActiveModel
record.errors.add(attribute, MESSAGES[key], errors_options)
end
end
+
+ private
+
+ def tokenize(value)
+ if value.kind_of?(String)
+ if options[:tokenizer]
+ options[:tokenizer].call(value)
+ elsif !value.encoding_aware?
+ value.mb_chars
+ end
+ end || value
+ end
end
module HelperMethods
@@ -96,7 +106,7 @@ module ActiveModel
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
# count words as in above example.)
# Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
+ # * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_length_of(*attr_names)
validates_with LengthValidator, _merge_attributes(attr_names)