2015-05-30 5 views
1

Опираясь на this answer, я написал следующий класс. При использовании его, я получаю сообщение об ошибке:Переменные экземпляра класса Ruby в подклассах

in 'serialize': undefined method '[]=' for nil:NilClass (NoMethodError).

Как я могу получить доступ к переменной @serializable_attrs в базовом классе?

Базовый класс: пример

# Provides an attribute serialization interface to subclasses. 
class Serializable 
    @serializable_attrs = {} 

    def self.serialize(name, target=nil) 
     attr_accessor(name) 
     @serializable_attrs[name] = target 
    end 

    def initialize(opts) 
     opts.each do |attr, val| 
      instance_variable_set("@#{attr}", val) 
     end 
    end 

    def to_hash 
     result = {} 
     self.class.serializable_attrs.each do |attr, target| 
      if target != nil then 
       result[target] = instance_variable_get("@#{attr}") 
      end 
     end 
     return result 
    end 
end 

Использование:

class AuthRequest < Serializable 
    serialize :company_id,  'companyId' 
    serialize :private_key,  'privateKey' 
end 

ответ

1

экземпляра класса переменных не передается по наследству, так что линия

@serializable_attrs = {} 

только устанавливает это в Serializable не его подклассы. В то время как вы могли бы использовать унаследованное крюк, чтобы установить это на подклассы или изменить метод serialize для инициализации @serializable_attrs я бы, вероятно, добавить

def self.serializable_attrs 
    @serializable_attrs ||= {} 
end 

И затем использовать это вместо отсылок непосредственно к переменной экземпляра.

+0

Приятно, что ваш предложенный метод инициализирует AND и возвращает значение. – Dor

+0

Еще одна хорошая вещь, которую я нашел: функция ActiveSupport 'class_attribute' (в' active_support/core_ext/class/attribute'). – Dor

+0

Если вы используете рельсы, то это хорошее решение (будьте осторожны, чтобы случайно не обновить атрибут на месте) –

Смежные вопросы