Allow symbol as values for tokenize of LengthValidator

This commit is contained in:
kakipo 2014-08-03 14:50:09 +09:00
parent f57cd78a73
commit c3fa5c3d25
4 changed files with 32 additions and 7 deletions

@ -1,3 +1,7 @@
* Allow symbol as values for `tokenize` of `LengthValidator`
*Kensuke Naito*
* Validate options passed to `ActiveModel::Validations.validate`.
Preventing, in many cases, the simple mistake of using `validate` instead of `validates`.

@ -38,7 +38,7 @@ def check_validity!
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 @@ def validate_each(record, attribute, value)
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 HelperMethods
# * <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.
#

@ -331,6 +331,19 @@ def test_validates_length_of_with_block
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 @@ def my_validation_with_arg(attr)
errors.add attr, "is missing" unless send(attr)
end
def my_word_tokenizer(str)
str.scan(/\w+/)
end
end