语法如何" has_many"与Class对象交互?

时间:2014-08-16 01:31:19

标签: ruby-on-rails ruby activerecord syntax

我的目标是在Rails的ActiveRecord中实现类似“has_many”的东西。我想更多地了解如何加载类/对象。

当我在下面使用“has_many”时会发生什么?

class Widget < MiniRecord
   has_many :trinkets
end

让我们说这是“MiniRecord”的实现:

class MiniRecord
  class << self
    def has_many associated_model
      @associations[:has_many] << associated_model_sym 
    end
  end

  def list_associations
    do_stuff(@associations) # Where do I instantiate @associations?
  end
end

我已经把它弄到了可行的地步,但是我有一些凌乱的代码,我想减少它。

我想了解这是如何工作的,但具体来说,我应该在哪里实例化@associations?

我希望能够在定义类(即静态变量)时定义的MiniRecord子类中“声明”属性,然后再对这些属性进行操作。

1 个答案:

答案 0 :(得分:3)

当你扩展MiniRecord,比如说MyRecord时,你得到了一个类层次结构图,如下所示(#SomeClass是本征类或SomeClass的单例类:

                             Class
                               |
MiniRecord    --class-->   #MiniRecord
   |                           |
MyRecord      --class-->   #MyRecord

list_associations上定义了MiniRecord方法,has_many上定义了#MiniRecord

当您在has_many的班级主体中致电MyRecord时,它会首先在#MyRecord中查找失败的方法。然后它会在#MiniRecord中查找并找到定义。如果它以某种方式失败,它将在Class中查找定义。这就是这种方法的工作原理。

关于问题

  

具体来说,我应该在哪里实例化@associations?

您有两种选择:

  1. 使用时初始化

    def has_many associated_model
      @associations ||= Hash.new{|h, k| h[k] = [] }
      @associations[:has_many] << associated_model_sym 
    end
    
  2. 在创建后代类时初始化

    class MiniRecord
      def self.inherited klass
        klass.instance_variable_set(:@associations, Hash.new{|h, k| h[k] = [] }
      end
    end
    
  3. 请注意,您无法直接访问实例方法@associations中的list_associations,因为它位于不同的范围内。您需要在@associations上公开MiniRecord,然后从那里获取值。

    class MiniRecord
      class << self
        def has_many associated_model
          @associations[:has_many] << associated_model
        end
    
        attr_reader :associations
      end
    
      def self.inherited klass
        klass.instance_variable_set(:@associations, Hash.new{|h, k| h[k] = [] })
      end
    
      def list_associations
        do_stuff(self.class.associations) # Where do I instantiate @associations?
      end
    
      def do_stuff sth
        p sth
      end
    end
    
    class MyRecord < MiniRecord
      has_many :thrinks
    end
    
    r = MyRecord.new
    r.list_associations
    p MyRecord.associations