How can I use the same tokenizer across models with validates_length_of?
I have the following validation in a model:
validates_length_of :description,
:minimum => 2, :on => :save,
:message => "must be at least 2 words",
:tokenizer => lambda {|text| text.scan(/\w+/)}
And this works fine. When I add a second field to the model that needs to be validated by number of words, I declare
tokenize_by_words = lambda {|text| text.scan(/\w+/)}
at the top of the model, and use
:tokenizer => tokenize_by_words
This also works fine, and keeps everything DRY. However, it all falls apart when I need to use the same tokenizer across multiple models. If I create config/initializers/tokenizers.rb thus:
class ActiveRecord::Base
tokenize_by_words = lambda {|text| text.scan(/\w+/)}
end
and remove th开发者_运维知识库e definitions in the models, I get /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1959:in 'method_missing': undefined local variable or method 'tokenize_by_words' for #<Class:0x10357e988> (NameError)
Using an instance variable or replacing the whole thing with a method doesn't work either.
I'm sure there's something blindingly obvious I'm missing, but the only documentation I can find on :tokenizer doesn't really consider DRY-ness :(
You should define the tokenizer as a method, i.e.
class ActiveRecord::Base
def foo(text)
text.scan(/\w+/)
end
end
Now use this method symbol as the value for :tokenizer
attribute.
validates_length_of :description,
:minimum => 2, :on => :save,
:message => "must be at least 2 words",
:tokenizer => :foo
You'll be able to use :symbol for tokenizer.
Please stay tuned ;)
class Article
include ActiveModel::Model
validates_length_of :content,
:minimum => 10,
:message => "must be at least 10 words",
:tokenizer => :tokenize_by_words
def tokenize_by_words(text)
text.scan(/\w+/)
end
end
Allow symbol as values for tokenizer
of LengthValidator
by kakipo · Pull Request #16381 · rails/rails
精彩评论