Ruby on rails 使用Rails中缺少的方法
我有一个带有几个日期属性的模型。我希望能够设置和获取字符串形式的值。我超越了其中一种方法(bill_date),如下所示:Ruby on rails 使用Rails中缺少的方法,ruby-on-rails,activerecord,overriding,method-missing,dynamic-attributes,Ruby On Rails,Activerecord,Overriding,Method Missing,Dynamic Attributes,我有一个带有几个日期属性的模型。我希望能够设置和获取字符串形式的值。我超越了其中一种方法(bill_date),如下所示: 这对我的需求来说非常好,但是我想对其他几个日期属性做同样的事情。。。如何利用method missing(方法缺失)来设置/获取任何日期属性?因为您已经知道所需方法的签名,所以最好定义它们,而不是使用method\u missing(方法缺失)。您可以这样做(在类定义中): 如果列出所有日期属性都不是问题,那么这种方法会更好,因为您处理的是常规方法,而不是方法中缺少的一些魔
这对我的需求来说非常好,但是我想对其他几个日期属性做同样的事情。。。如何利用method missing(方法缺失)来设置/获取任何日期属性?因为您已经知道所需方法的签名,所以最好定义它们,而不是使用
method\u missing(方法缺失)
。您可以这样做(在类定义中):
如果列出所有日期属性都不是问题,那么这种方法会更好,因为您处理的是常规方法,而不是方法中缺少的一些魔法
如果要将其应用于名称以\u date
结尾的所有属性,可以这样检索它们(在类定义中):
下面是方法\u缺少的解决方案(未测试,尽管前一个也未测试):
此外,重写respond\u to?
方法并返回true
方法名称也很好,您可以在method\u missing
中处理该方法(在1.9中,您应该重写respond\u to\u 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
classmymodel
完成此操作后,my_instance.bill_date_human
将调用attribute_human
,attr_name设置为“bill_date”。ActiveModel将为您处理method_missing
,Response_to
之类的事情。唯一的缺点是,所有列都存在这些人方法。oo太好了!我没有遇到define_method before:)我仍然希望看到方法缺少实现,但是+1可以获得更好的解决方案添加method_missing
版本,但是如果可以定义这些方法,请不要使用它。@KL-7在method_missing
中,不处理该方法时,应直接使用super返回。现在,始终执行下面的属性处理。method\u missing
是您应该采取的最后一根稻草。事实上,定义方法更为清晰,可以通过清晰的关注点分离实现更好的代码设计,更易于理解,也更快。因此,如果你能定义你的方法,你应该一直这样做。正如从KL-7中学到的,有比方法_缺失更好的方法,但是考虑到我对这个模型有4个不同的日期属性,手动定义每一个都不是解决方案。DRYWell,KL-7方法实际上是这里的首选方法。因为他提出的正是我的意思:定义方法。
[: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
column_names.grep(/_date$/)
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
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