Как мне повторить поведение class_inheritable_accessor в Rails 3.1? - PullRequest
14 голосов
/ 08 июля 2011

Начиная с 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?

Ответы [ 2 ]

10 голосов
/ 08 июля 2011

class_attribute не будет загрязнять своего родителя, если он используется по назначению. Убедитесь, что вы не меняете изменяемые элементы на месте.

types_and_classes.keys.each do |t|
  self.presented = presented.merge({t => types_and_classes[t]})
end
0 голосов
/ 11 сентября 2012

Дайте этому попытку, отличный способ установить атрибуты в классе и не загрязнять их наследованием или экземплярами.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...