我想在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