Я пытаюсь записать класс Ruby, который работает так же к модели Rails AactiveRecord в способе, которым обрабатываются атрибуты:
class Person
attr_accessor :name, :age
# init with Person.new(:name => 'John', :age => 30)
def initialize(attributes={})
attributes.each { |key, val| send("#{key}=", val) if respond_to?("#{key}=") }
@attributes = attributes
end
# read attributes
def attributes
@attributes
end
# update attributes
def attributes=(attributes)
attributes.each do |key, val|
if respond_to?("#{key}=")
send("#{key}=", val)
@attributes[key] = name
end
end
end
end
То, что я имею в виду, является этим, когда я init класс, хеш "атрибутов" обновляется с соответствующими атрибутами:
>>> p = Person.new(:name => 'John', :age => 30)
>>> p.attributes
=> {:age=>30, :name=>"John"}
>>> p.attributes = { :name => 'charles' }
>>> p.attributes
=> {:age=>30, :name=>"charles"}
Пока все хорошо. То, что я хочу произойти, - чтобы хеш атрибутов обновил, когда я установил отдельное свойство:
>>> p.attributes
=> {:age=>30, :name=>"John"}
>>> p.name
=> "John"
>>> p.name = 'charles' # <--- update an individual property
=> "charles"
>>> p.attributes
=> {:age=>30, :name=>"John"} # <--- should be {:age=>30, :name=>"charles"}
Я мог сделать это путем записи метода set и метода считывания для каждого атрибута вместо использования attr_accessor
, но это высосет для модели, которая имеет много полей. Какой-либо быстрый способ выполнить это?
Проблема в том, что вы храните свои атрибуты как отдельные ivars, так и в хэше @attributes
. Вы должны выбрать и использовать только один способ.
Если вы хотите использовать хеш, вы должны создать свой собственный способ создания аксессоров, который «перенаправит» их в один метод, который будет устанавливать и получать из хеша:
class Class
def my_attr_accessor(*accessors)
accessors.each do |m|
define_method(m) do
@attributes[m]
end
define_method("#{m}=") do |val|
@attributes[m]=val
end
end
end
end
class Foo
my_attr_accessor :foo, :bar
def initialize
@attributes = {}
end
end
foo = Foo.new
foo.foo = 123
foo.bar = 'qwe'
p foo
#=> #<Foo:0x1f855c @attributes={:foo=>123, :bar=>"qwe"}>
Если вы хотите использовать ivars, вы должны снова запустить свой собственный метод attr_accessor
, который, кроме того, запомнил бы, какие ivars должны быть «атрибутами», и использовать этот список в методе attributes
. А метод attributes
на лету создает из них хеш и возвращает его.
Здесь вы можете найти хорошую статью о реализации аксессоров.