2011-07-07 5 views
11

Rails 3.1以降、class_inheritable_accessorでは、代わりにclass_attributeを使用するようにとの警告が表示されます。しかし、class_attributeは、私が実証する重要なやり方で異なって振る舞います。Rails 3.1でclass_inheritable_accessorの動作をどのようにレプリケートしますか?

class_inheritable_attributeの典型的な使用はそうのような、プレゼンターのクラス次のようになります。

module Presenter 
    class Base 
    class_inheritable_accessor :presented 
    self.presented = {} 

    def self.presents(*types) 
     types_and_classes = types.extract_options! 
     types.each {|t| types_and_classes[t] = t.to_s.tableize.classify.constantize } 
     attr_accessor *types_and_classes.keys 
     types_and_classes.keys.each do |t| 
     presented[t] = types_and_classes[t] 
     end 
    end 
    end 
end 

class PresenterTest < Presenter::Base 
    presents :user, :person 
end 

Presenter::Base.presented => {} 
PresenterTest.presented => {:user => User, :person => Person} 

しかしclass_attributeを使用して、サブクラスは親を汚染します:

Presenter::Base => {:user => User, :person => Person} 

ですべての動作を希望されていません。正しい振る舞いをする別のアクセサー型がありますか、別のパターンに切り替える必要がありますか? class_inheritable_accessorなしで同じ振る舞いをどのように再現するべきですか?

答えて

7

class_attributeは意図したとおりに使用されていればその親を汚染しません。変更可能なアイテムをインプレースで変更していないことを確認してください。

types_and_classes.keys.each do |t| 
    self.presented = presented.merge({t => types_and_classes[t]}) 
end 
0

これは、継承またはインスタンスによって汚染されていない属性をクラスに設定するのに最適です。

class Class 

    private 

    # Sets Unique Variables on a resource 
    def inheritable_attr_accessor(*attrs) 
    attrs.each do |attr| 

     # Class Setter, Defining Setter 
     define_singleton_method "#{attr}=".to_sym do |value| 
     define_singleton_method attr do 
      value 
     end 
     end 

     # Default to nil 
     self.send("#{attr}=".to_sym, nil) 

     # Instance Setter 
     define_method "#{attr}=".to_sym do |value| 
     eval("@_#{attr} = value") 
     end 

     # Instance Getter, gets class var if nil 
     define_method attr do 
     eval("defined?(@_#{attr})") ? eval("@_#{attr}") : self.class.send(attr) 
     end 

    end 
    end 

end 
関連する問題