在Rails中编写可继承的属性与基本赋值

时间:2010-11-27 23:22:07

标签: ruby-on-rails ruby

只是好奇Rails gem中这两者之间的区别:

write_inheritable_attribute(:sample, "sample")
self.sample = "sample"

我在write_inheritable_attribute上找不到任何好的文档,只是阅读了一些宝石源,发现前者使用了几次。谢谢!

3 个答案:

答案 0 :(得分:13)

子类不继承实例变量:

>> class B ; @candy = 1 ; end
>> B.instance_variable_get :@candy          # => 1
>> class C < B ; end
>> C.instance_variable_get :@candy          # => nil

在rails中,可继承属性提供了一个解决方案:

>> class B ; end
>> B.write_inheritable_attribute(:candy, 7) # => 7
>> class C < B ; end
>> C.read_inheritable_attribute(:candy)     # => 7

答案 1 :(得分:5)

对于一个简单的类或模块,没有区别,但是对于可以加载多个其他模块的更复杂的模块,像write_inheritable_attribute这样的方法可以帮助您轻松可靠地修改对象,而无需担心范围,私人/受保护的方法以及像method_missing这样的红宝石元编程魔法的各种干扰。

简而言之,当您编写foo.sample = "sample"时,可能会在设置属性之前,之后或之后发生各种事情,尤其是在对象使用ActiveModel或ORM时。当您使用foo.write_inheritable_attribute(:sample, "sample")时,您可以更好地控制发生的事情。

答案 2 :(得分:2)

实现了可继承属性主要是为了解决在类继承中共享ruby类变量的问题。考虑这个例子

class Counter
  @@count = 0
  def self.count
    @@count
  end

  def self.increment
    puts "==> #{self} increment"
    @@count += 1
  end
end

class DogCounter < Counter
end

puts "Counter.count:    #{Counter.count}"
puts "DogCounter.count: #{DogCounter.count} -> nice, DogCounter inherits @@count from Counter"

DogCounter.increment
puts "DogCounter.count: #{DogCounter.count} -> as expected"
puts "Counter.count:    #{Counter.count} -> but Counter.count is also changed!"

Counter.increment
puts "Counter.count:    #{Counter.count}"
puts "DogCounter.count: #{DogCounter.count} -> @@count is shared with all the descendants of Counter"

这将产生此输出

Counter.count:    0
DogCounter.count: 0 -> nice, DogCounter inherits @@count from Counter
==> DogCounter increment
DogCounter.count: 1 -> as expected
Counter.count:    1 -> but Counter.count is also changed!
==> Counter increment
Counter.count:    2
DogCounter.count: 2 -> @@count is shared with all the descendants of Counter

请注意,因为Rails 3.2 write_inheritable_attribute已被删除。看到 http://dev.mensfeld.pl/2012/01/upgrading-to-rails-3-2-0-from-rails-3-1-3/

使用class属性(曾经是可继承属性)我们可以实现类似这样的东西:

class Counter
  class_attribute :count
  self.count = 0

  def self.increment
    puts "==> #{self} increment"
    self.count += 1
  end
end

class DogCounter < Counter
end

puts "Counter.count:    #{Counter.count}"
puts "DogCounter.count: #{DogCounter.count} -> nice, DogCounter inherits count from Counter"

DogCounter.increment
puts "DogCounter.count: #{DogCounter.count} -> as expected"
puts "Counter.count:    #{Counter.count} -> nice, it doesn't change count for Counter"

Counter.increment
puts "Counter.count:    #{Counter.count}"
puts "DogCounter.count: #{DogCounter.count} -> now each subclass can have their own class attribute that inherits default value from the superclass"

这将产生此输出

Counter.count:    0
DogCounter.count: 0 -> nice, DogCounter inherits count from Counter
==> DogCounter increment
DogCounter.count: 1 -> as expected
Counter.count:    0 -> nice, it doesn't change count for Counter
==> Counter increment
Counter.count:    1
DogCounter.count: 1 -> now each subclass can have their own class attribute that inherits default value from the superclass