我想在Rails中增强ActiveRecord setter以确保只保存有效值。需要这样的一个地方是电话号码。用户可以输入各种格式的电话号码,例如
(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
)。该方法现在负责覆盖setter 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的实例的方法进行别名?
答案 0 :(得分:1)
我认为你的错误不是undefined method alias_method
它是不同的东西而你误解了它(?)
真正的问题是ActiveRecord
上的getter和setter方法是动态。在从数据库加载实际AR对象之前,不会创建getter和setter方法(即phone
和phone=
)。此时,AR枚举数据库字段并创建相应的字段方法。
这些字段方法在您的源中定义类时不可用,因此您不能alias_method
不存在的方法。然而,你可以做这样的事情(未经测试):
module PhoneSanitizer
module ClassMethods
def sanitize_phone(*fields)
fields.each do |field|
original_method = "#{field}=".to_sym
define_method(original_method) do |value|
self.write_attribute(field, phone_to_number(value))
end
end
end
end
...
end
这应该完成与你原先打算完全相同的事情:
http://apidock.com/rails/ActiveRecord/AttributeMethods/Write/write_attribute