5

私はいくつかの日付属性を持つモデルを持っています。私は文字列として値を設定して取得できるようにしたいと思います。 IオーバーRODEそうのようなメソッド(bill_date)の1:Railsに欠けているメソッドを使用する

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 

私はの利点を取るだろうか...これは私のニーズのための偉大な行いが、私はいくつかの他の日付属性のために同じことをやりたいですどのような日付属性も設定/取得できるようにメソッドがありませんか?

+1

'method_missing'はあなたが取るべき最後のわらについてです。実際に定義されたメソッドははるかにクリーンで、明確な分離を伴うより良いコード設計につながり、理解しやすく、高速になります。したがって、メソッドを定義できる場合は、常にそれを実行する必要があります。 –

+0

KL-7から学んだように、method_missingより優れたアプローチがありますが、このモデルには4つの異なる日付属性があると考えて、それぞれを手動で定義することは解決策ではありません。 DRY – tybro0103

+0

さて、ここではKL-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 

すべての日付の属性を一覧表示することは、あなたがmethod_missing内部の定期的な方法の代わりに、いくつかの魔法を扱っているように、このアプローチが優れている問題ではない場合。

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

column_names.grep(/_date$/) 

そして、ここではmethod_missing溶液(テストしていない、以前かかわらずです1)は、いずれかのテストされていません。

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?メソッドをオーバーライドし、メソッド名のためtrueを返すようにうれしいです(1.9では代わりにrespond_to_missing?を上書きする必要があります)。

+0

素晴らしいよ!私はdefine_methodに遭遇していませんでした:)メソッドが実装されていないのを見たいと思っていますが、より良い解決策のために+1します。 – tybro0103

+1

'method_missing'バージョンを追加しました。 –

+1

@ KL-7 'method_missing'では、メソッドを処理していないときにsuperで直接返すべきです。今、以下の属性処理が常に実行されます。 –

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 

これを行った操作を行うことができるはず

my_instance.bill_date_humanは「bill_date」に設定ATTR_NAMEでattribute_humanを呼び出します。 ActiveModelはmethod_missing,respond_toなどを処理します。唯一の欠点は、これらのメソッドがすべての列に存在することです。

関連する問題