Ruby on rails 使用Rails中缺少的方法

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(方法缺失)。您可以这样做(在类定义中): 如果列出所有日期属性都不是问题,那么这种方法会更好,因为您处理的是常规方法,而不是方法中缺少的一些魔

我有一个带有几个日期属性的模型。我希望能够设置和获取字符串形式的值。我超越了其中一种方法(bill_date),如下所示:


这对我的需求来说非常好,但是我想对其他几个日期属性做同样的事情。。。如何利用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