2017-05-22 15 views
0

私はRailsアプリケーションを持っており、デフォルト属性を設定する必要があります。時には、ユーザーは、尊重される属性の値を提供することがありますが、モデルやユーザーは、これらの属性が元の値を無視した既定値で上書きされることを望む場合もあります。デフォルトの属性アクセサーを作成する

この問題は、ユーザーとプログラムが適切な状態に切り替えることを可能にするデフォルト値を設定するために、打ち切られた(!)メソッドと非打ち込みメソッドを必要としていたと推測しました。 non-banged setterは、デフォルト値を設定します.nilでないときはデフォルト値を設定し、bangedバージョンは常にデフォルト値で属性を上書きします。違いは軽微です:

class BangDiBang 
    attr_accessor :value 

    def set_default 
    self.value ||= do_some_suff_to_determine_default_value 
    end 

    def set_default! 
    self.value = do_some_suff_to_determine_default_value 
    end 

    ... 
end 

このコードの問題は、私が設定する変数の束を持っていた場合、私は、各変数のために二度同じコードを繰り返して終わるだろうということです。

私の質問は、このコードをどのように部分的にするかです。 1つの方法で論理を保存し、2つの方法を有するset_valueおよびset_value!異なる割り当て演算子で中央ロジックを呼び出す。

私は1つの解決策を思いつきました:テキストとして中央ロジックを書き、セッターメソッドから代入演算を置き換えて評価します(しかし、これは正しいとは思いません)。どうやって自分を繰り返さないの?

+0

あなたがそれを必要とするあらゆる場所に関心を持ち、それらを含めるのはどうですか? – Severin

答えて

0

あなたがset_defaultを呼び出していて、どの変数を指定していないので、これについては、複数のパラメータに対してはうまくいかないでしょう。理想的には、各変数の動作を定義する必要があります。そここの種のものを扱うライブラリがありますが、あなた自身はかなり簡単にロールバックすることができます

class Example 
    def self.default_param(name, default_value) 
    define_method("default_#{name}") { default_value } 

    define_method(name) do 
     instance_variable_get("@#{name}") || default_value 
    end 

    attr_writer name 
    end 

    default_param :foo, 'foo default' 
end 

ex = Example.new 
ex.foo #=> "foo default" 
ex.foo = 'bar' 
ex.foo #=> "bar" 
ex.default_foo #=> "foo default" 

私はより明確にするset_defaultset_default!と改名しました:デフォルト値と各変数のために、3つの方法が作成されます。 (変数名としてfooを用いた例):

  1. fooは - それはtruthyある場合@fooの値を返し、そうでなければdefault_foo
  2. foo=からの値を設定します
  3. default_foo - あなたは区分すると、上記の更なるコードの一部を乾燥させ、ハッシュを取るためにdefault_params(複数)メソッドを作成し、懸念へのクラスのマクロを抽出することができ、指定のデフォルト

を返します。

module DefaultParams 
    def default_param(name, default_value) 
    define_method("default_#{name}") { default_value } 

    define_method(name) do 
     instance_variable_get("@#{name}") || default_value 
    end 

    attr_writer name 
    end 

    def default_params(params) 
    params.each { |default| default_param(*default) } 
    end 
end 

class Example 
    extend DefaultParams 
    default_params foo: 'default foo', bar: 'my favorite bar' 
end 
+0

私は最初に考えなかった少しのヒントが必要でした:デフォルトを持つべき各属性のdefault_valueメソッドを持つこと。ありがとう。 –

0

私はcoreywardから大きなインスピレーションを得て解決策を実装しました。私は最初にデフォルト値の配列を設定するための2つのメソッドを持つのではなく、デフォルト値を単一のメソッドに分割する必要があることを最初は認識していませんでした。これにより、アプリケーションの設計に大きな柔軟性がもたらされます。だからこそ答えに感謝します。私はapplication_record.rb

def set_attr_from_defaults 
    default_attrs.each do |atr| 
    eval("self.#{atr[0..atr.length-9]} ||= self.#{atr}") 
    end 
end 

def set_attr_from_defaults! 
    default_attrs.each do |atr| 
    eval("self.#{atr[0..atr.length-9]} = self.#{atr}") 
    end 
end 

def set_default_attr params 
    params.each { |key, value| self.define_singleton_method(key){value} } 
end 

def default_attrs 
    self.attributes.keys.map{|i| (i+'_default').to_sym} & self.methods 
end 

default_attrsに追加したレールのセットアップについては

は、シンボルオフデフォルト属性のリストを生成します。 set_default_attrはシングルトンメソッドを定義し、attrname_default: 'default_value' ...のようなハッシュでの解析を意図して使用します。set_attr_from_defaultsは、属性がvar: var_defaultのようなペアを持つ場合、デフォルト値から属性を設定します。数字9_default + 1の長さです。

関連する問題