mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #16381 from kakipo/validate-length-tokenizer
Allow symbol as values for `tokenizer` of `LengthValidator`
This commit is contained in:
commit
7919c29d50
4 changed files with 32 additions and 7 deletions
|
@ -1,3 +1,7 @@
|
|||
* Allow symbol as values for `tokenize` of `LengthValidator`
|
||||
|
||||
*Kensuke Naito*
|
||||
|
||||
* Assigning an unknown attribute key to an `ActiveModel` instance during initialization
|
||||
will now raise `ActiveModel::AttributeAssignment::UnknownAttributeError` instead of
|
||||
`NoMethodError`
|
||||
|
|
|
@ -38,7 +38,7 @@ module ActiveModel
|
|||
end
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
value = tokenize(value)
|
||||
value = tokenize(record, value)
|
||||
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
|
||||
errors_options = options.except(*RESERVED_OPTIONS)
|
||||
|
||||
|
@ -59,10 +59,14 @@ module ActiveModel
|
|||
end
|
||||
|
||||
private
|
||||
|
||||
def tokenize(value)
|
||||
if options[:tokenizer] && value.kind_of?(String)
|
||||
options[:tokenizer].call(value)
|
||||
def tokenize(record, value)
|
||||
tokenizer = options[:tokenizer]
|
||||
if tokenizer && value.kind_of?(String)
|
||||
if tokenizer.kind_of?(Proc)
|
||||
tokenizer.call(value)
|
||||
elsif record.respond_to?(tokenizer)
|
||||
record.send(tokenizer, value)
|
||||
end
|
||||
end || value
|
||||
end
|
||||
|
||||
|
@ -108,8 +112,8 @@ module ActiveModel
|
|||
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
|
||||
# <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
|
||||
# <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
||||
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
|
||||
# (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
|
||||
# * <tt>:tokenizer</tt> - Specifies a method, proc or string to how to split up the attribute string.
|
||||
# (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> or <tt>tokenizer: :word_tokenizer</tt> to count words
|
||||
# as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
|
||||
# which counts individual characters.
|
||||
#
|
||||
|
|
|
@ -330,6 +330,19 @@ class LengthValidationTest < ActiveModel::TestCase
|
|||
assert_equal ["Your essay must be at least 5 words."], t.errors[:content]
|
||||
end
|
||||
|
||||
|
||||
def test_validates_length_of_with_symbol
|
||||
Topic.validates_length_of :content, minimum: 5, too_short: "Your essay must be at least %{count} words.",
|
||||
tokenizer: :my_word_tokenizer
|
||||
t = Topic.new(content: "this content should be long enough")
|
||||
assert t.valid?
|
||||
|
||||
t.content = "not long enough"
|
||||
assert t.invalid?
|
||||
assert t.errors[:content].any?
|
||||
assert_equal ["Your essay must be at least 5 words."], t.errors[:content]
|
||||
end
|
||||
|
||||
def test_validates_length_of_for_fixnum
|
||||
Topic.validates_length_of(:approved, is: 4)
|
||||
|
||||
|
|
|
@ -37,4 +37,8 @@ class Topic
|
|||
errors.add attr, "is missing" unless send(attr)
|
||||
end
|
||||
|
||||
def my_word_tokenizer(str)
|
||||
str.scan(/\w+/)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue