5

いくつかの日付属性を持つモデルがあります。値を文字列として設定および取得できるようにしたいと思います。メソッドの 1 つ (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

これは私のニーズには最適ですが、他のいくつかの日付属性についても同じことをしたいです...メソッドが見つからないことを利用して、日付属性を設定/取得できるようにするにはどうすればよいですか?

4

2 に答える 2

11

目的のメソッドのシグネチャを既に知っているので、 を使用する代わりにそれらを定義する方がよい場合があります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

すべての日付属性をリストすることが問題にならない場合は、内部の魔法の代わりに通常のメソッドを扱っているため、このアプローチの方が優れていますmethod_missing

で終わる名前を持つすべての属性にそれを適用したい場合は、_dateそのようにそれらを取得できます(クラス定義内):

column_names.grep(/_date$/)

そして、ここに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

さらに、メソッドをオーバーライドし、内部で処理するメソッド名respond_to?を返すと便利です(1.9 では代わりにオーバーライドする必要があります)。truemethod_missingrespond_to_missing?

于 2012-01-16T20:29:01.847 に答える
5

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

これを行うと、「bill_date」に設定された attr_name でmy_instance.bill_date_human呼び出します。attribute_humanActiveModel は、 などを処理method_missingrespond_toます。唯一の欠点は、これらの _human メソッドがすべての列に存在することです。

于 2012-01-16T22:12:44.327 に答える