Как копировать поведение class_inheritable_accessor в Rails 3.1?
Начиная с Rails 3.1, class_inheritable_accessor
выдает предупреждения об устаревании, вместо этого говорит мне использовать class_attribute
. Но class_attribute
ведет себя по-разному так, что я продемонстрирую.
Типичным использованием 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
?
Ответы
Ответ 1
class_attribute
не будет загрязнять его родительский объект, если он используется по назначению. Убедитесь, что вы не меняете изменяемые элементы на месте.
types_and_classes.keys.each do |t|
self.presented = presented.merge({t => types_and_classes[t]})
end
Ответ 2
Попробуйте это, отличный способ иметь атрибуты, установленные в классе, и не загрязнять их наследованием или экземплярами.
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