【问题标题】:How does syntax like "has_many" interact with the Class objects?“has_many”之类的语法如何与 Class 对象交互?
【发布时间】:2014-08-16 10:35:30
【问题描述】:

我的目标是在 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 的子类中“声明”属性(即静态变量),然后再对这些属性进行操作。

【问题讨论】:

    标签: ruby-on-rails ruby activerecord syntax


    【解决方案1】:

    当你扩展MiniRecord,比如MyRecord,你会得到一个类似于下面的类层次结构图(#SomeClass是SomeClass的特征类或单例类):

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

    其中list_associations 方法在MiniRecord 上定义,has_many 在#MiniRecord 上定义。

    当你在MyRecord的类体中调用has_many时,它会先查找#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
      

    请注意,您不能在实例方法list_associations 中直接访问@associations,因为它在不同的范围内。您需要在MiniRecord 上公开@associations,然后从那里获取值。

    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
    

    【讨论】:

      猜你喜欢
      • 2011-02-06
      • 1970-01-01
      • 2013-09-03
      • 2021-09-05
      • 2012-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多