模型Country
有一个属性code
,它会被before_save
回调自动转换为小写。是否可以在“魔术”方法上强制执行此行为而无需重写大块的ActiveRecord :: Base?
class Country < ActiveRecord::Base
attr_accessible :code
validates :code, :presence => true
validates_uniqueness_of :code, :case_sensitive => false
before_save do |country|
country.code.downcase! unless country.code.nil?
end
end
RSpec的
describe Country do
describe 'data normalization'
before :each do
@country = FactoryGirl.create(:country, :code => 'DE')
end
# passes
it 'should normalize the code to lowercase on insert' do
@country.code.should eq 'de'
end
# fails
it 'should be agnostic to uppercase finds' do
country = Country.find_by_code('DE')
country.should_not be_nil
end
# fails
it 'should be agnostic to uppercase finds_or_creates' do
country = Country.find_or_create_by_code('DE')
country.id.should_not be_nil # ActiveRecord Bug?
end
end
答案 0 :(得分:0)
这是我提出的,尽管我真的很讨厌这种方法(正如问题所述)。一个简单的替代方法是将列,表或整个数据库设置为忽略大小写(但这是db dependendt)。
class Country < ActiveRecord::Base
attr_accessible :code
validates :code, :presence => true
validates_uniqueness_of :code, :case_sensitive => false
before_save do |country|
country.code.downcase! unless country.code.nil?
end
class ActiveRecord::Base
def self.method_missing_with_code_finders(method_id, *arguments, &block)
if match = (ActiveRecord::DynamicFinderMatch.match(method_id) || ActiveRecord::DynamicScopeMatch.match(method_id))
attribute_names = match.attribute_names
if code_index = attribute_names.find_index('code')
arguments[code_index].downcase!
end
end
method_missing_without_code_finders(method_id, *arguments, &block)
end
class << self
alias_method_chain(:method_missing, :code_finders)
end
end
end