2011-07-07 11 views
11

Począwszy od Rails 3.1, class_inheritable_accessor generowane są ostrzeżenia o wycofaniu, informujące mnie o użyciu class_attribute. Ale class_attribute zachowuje się inaczej w ważny sposób, który pokażę.Jak zreplikować zachowanie class_inheritable_accessor w Rails 3.1?

Typowym zastosowaniem class_inheritable_attribute byłaby klasa prezenter, tak:

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} 

Ale używając class_attribute, podklasy zanieczyszczają ich rodziców:

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

co nie jest pożądane zachowanie w ogóle. Czy istnieje inny typ akcesora, który zachowuje się we właściwy sposób, czy też muszę przejść na inny wzorzec? Jak mam replikować to samo zachowanie bez class_inheritable_accessor?

Odpowiedz

7

class_attribute nie zanieczyści swojego rodzica, jeśli jest używany zgodnie z przeznaczeniem. Upewnij się, że nie zmieniasz elementów zmiennych w miejscu.

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

Spróbuj, to świetny sposób, aby ustawić atrybuty na klasie i nie być zanieczyszczonym spadkiem ani instancjami.

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