tyb*_*103 5 activerecord overriding ruby-on-rails method-missing dynamic-attributes
我有一个具有多个日期属性的模型.我希望能够设置和获取值作为字符串.我过度使用其中一个方法(bill_date),如下所示:
def bill_date_human
date = self.bill_date || Date.today
date.strftime('%b %d, %Y')
end
def bill_date_human=(date_string)
self.bill_date = Date.strptime(date_string, '%b %d, %Y')
end
Run Code Online (Sandbox Code Playgroud)
这对我的需求很有帮助,但我想对其他几个日期属性做同样的事情...我如何利用方法缺失,以便可以设置/得到任何日期属性?
KL-*_*L-7 10
由于您已经知道所需方法的签名,因此最好定义它们而不是使用它们method_missing.你可以这样做(在你的类定义中):
[:bill_date, :registration_date, :some_other_date].each do |attr|
define_method("#{attr}_human") do
(send(attr) || Date.today).strftime('%b %d, %Y')
end
define_method("#{attr}_human=") do |date_string|
self.send "#{attr}=", Date.strptime(date_string, '%b %d, %Y')
end
end
Run Code Online (Sandbox Code Playgroud)
如果列出所有日期属性不是问题,这种方法更好,因为你正在处理常规方法而不是内部的一些魔法method_missing.
如果要将其应用于名称以_date您结尾的所有属性,可以像这样检索它们(在类定义中):
column_names.grep(/_date$/)
Run Code Online (Sandbox Code Playgroud)
这里是method_missing解决方案(未经测试,但前一个测试也未测试):
def method_missing(method_name, *args, &block)
# delegate to superclass if you're not handling that method_name
return super unless /^(.*)_date(=?)/ =~ method_name
# after match we have attribute name in $1 captured group and '' or '=' in $2
if $2.blank?
(send($1) || Date.today).strftime('%b %d, %Y')
else
self.send "#{$1}=", Date.strptime(args[0], '%b %d, %Y')
end
end
Run Code Online (Sandbox Code Playgroud)
另外,覆盖respond_to?方法和返回true方法名称是很好的,你在里面处理method_missing(在1.9中你应该覆盖respond_to_missing?).
您可能对ActiveModel的AttributeMethods模块感兴趣(该活动记录已经用于一堆东西),这几乎(但不完全)是您需要的.
简而言之,你应该能够做到
class MyModel < ActiveRecord::Base
attribute_method_suffix '_human'
def attribute_human(attr_name)
date = self.send(attr_name) || Date.today
date.strftime('%b %d, %Y')
end
end
Run Code Online (Sandbox Code Playgroud)
完成此操作后,my_instance.bill_date_human将调用attribute_humanattr_name设置为'bill_date'.将加载ActiveModel处理之类的东西method_missing,respond_to给你的.唯一的缺点是所有列都存在这些_human方法.