代码之家  ›  专栏  ›  技术社区  ›  Kevin Sylvestre

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

  •  7
  • Kevin Sylvestre  · 技术社区  · 15 年前

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

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

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

    3 回复  |  直到 15 年前
        1
  •  5
  •   bowsersenior    15 年前

    对于一个简单的类或模块,没有区别,但是对于更复杂的模块,可能会加载多个其他模块,方法如下 write_inheritable_attribute 可以帮助您轻松可靠地修改对象,而不必担心范围、私有/受保护的方法以及来自ruby元编程的各种干扰,比如 method_missing .

    简而言之,当你写 foo.sample = "sample" 在设置属性之前、之后或不设置属性的情况下,可能会发生各种情况,特别是当对象使用ActiveModel或ORM时。当你使用 foo.write_inheritable_attribute(:sample, "sample") 你对发生的事情有更大的控制力。

        2
  •  13
  •   ecoologic    12 年前

    子类不继承实例变量:

    >> 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
    
        3
  •  2
  •   Reynard    12 年前

    可继承属性的实现主要是为了解决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_属性就被删除了。见 http://dev.mensfeld.pl/2012/01/upgrading-to-rails-3-2-0-from-rails-3-1-3/

    使用类属性(以前是可继承属性)我们可以实现如下内容:

    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