2011-07-07 15 views
11

Comenzando con rieles 3.1, class_inheritable_accessor produce avisos de obsolescencia, diciéndome a utilizar class_attribute lugar. Pero class_attribute se comporta de manera diferente de una manera importante que demostraré.¿Cómo puedo replicar el comportamiento de class_inheritable_accessor en Rails 3.1?

Un uso típico de class_inheritable_attribute sería una clase de presentador, así:

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} 

Pero el uso de class_attribute, subclases contaminará sus padres:

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

que no se desea el comportamiento en absoluto. ¿Hay otro tipo de acceso que se comporte de la manera correcta, o debo cambiar a otro patrón por completo? ¿Cómo debería replicar el mismo comportamiento sin class_inheritable_accessor?

Respuesta

7

class_attribute no contaminará su padre si se utiliza según lo previsto. Asegúrese de no cambiar los elementos mutables en el lugar.

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

Dale una oportunidad, una gran manera de tener atributos establecidos en la clase, y no contaminados por herencia o instancias.

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