我想在Rails中增强ActiveRecord设置器以确保只保存有效值。需要这样一个地方是电话号码。用户可以在多种格式,如输入电话号码,用附加功能包装ActiveRecord方法
(123) 456-7890
+1 123-456-7890
但我只想要存储的数字,当它到数据库放弃休息。我现在使用的方法是使用alias_method
覆盖setter方法。此外,我试图把它放到一个模块中,以便任何包含电话号码的模型类都可以包含这个模块,并定义应该清理的字段。我希望用一种接口是,
# Person has a "phone" attribute to store phone numbers
class Person < ActiveRecord::Base
# first include this module
include PhoneSanitizer
# then call the class method and tell it which
# fields need need to be sanitized
sanitize_phone_field :phone
end
我我的模型类中做的唯一一件事就是包括PhoneSanitizer
模块(它增加了一个类的方法 - sanitize_phone_field
在Person
类)。该方法现在负责覆盖设置器phone=
方法。这是我没有得到工作的部分。
module PhoneSanitizer
module ClassMethods
# wrap each of the passed-in fields with setters that
# clean up the phone number value of non-digits.
def sanitize_phone(*fields)
fields.each do |field|
new_method = "original_#{field}=".to_sym
original_method = "#{field}=".to_sym
alias_method new_method, original_method
define_method(original_method) do |value|
self.send(new_method, phone_to_number(value))
end
end
end
end
def self.included(base)
base.extend(ClassMethods)
end
def phone_to_number(number)
number.gsub(/[^\d]/, '')
end
end
当sanitize_phone
被调用时,它抛出一个错误说:phone=
没有为Person
类中定义,这是很有意义的。我会如何去替代Person的实例的方法?
在我看来,这将是更清洁和更安全简单在PhoneSanitizer模块中定义实例方法,将模块包含在Person类中,然后从before_save回调中调用方法。 – KenB
其实我非常喜欢这个想法。不知道为什么我以前没有考虑过在验证回调中做这件事。这比使用方法混合玩耍要干净得多。我已经实施了这个解决方案。然而,为了学习和改进我的元编程的业力要点,我仍然有兴趣了解上面我做错了什么。 – Anurag
嗯。我似乎无法重现您的问题:https://gist.github.com/1185316。测试了红宝石1.8和1.9。虽然我有一个想法,你的问题在哪里..我认为你说你得到的错误不是Ruby实际告诉你真正的错误是。 – Casper