1

我已经得到了正在成为一个复杂模型的东西,并且正在尝试将其干燥。对于我的 has_many 选项,我不想让它们重复,而是简单地从类的方法中加载它们。

class ExampleClass < ActiveRecord::Base
  has_many :related_things, get_association_hash(arg1)
  has_many :other_things, get_association_hash(arg2)

  def get_association_hash(arg)
    { :class_name => 'SomeClass', :conditions => ['table.column = ?', arg] }
  end
end

不幸的是,这会导致在undefined method ‘get_association_hash’ for #<Class:0x007f9ae9efe6c0>加载类时。

(作为一个健全的检查,如果我只是自己调用它,而不将它包含在 has_many 中,那么该方法很好。此外,实际的类要大得多,所以 DRY 比这个小例子更有帮助。)

我确实注意到错误消息提到了Class,而不是我的 derived ExampleClass,所以也许它与 has_many 的加载方式以及我在哪里定义我的方法有关?

4

1 回答 1

1

has_many只是一个类方法,所以这个:

has_many :related_things, get_association_hash(arg1)

就像其他任何方法一样,它只是一个方法调用,并且该上下文中的接收者是您的ExampleClass. 这意味着它get_association_hash需要是一个类方法。您还必须在调用之前定义它,否则您has_many将无法在您想要的地方调用它:

class ExampleClass < ActiveRecord::Base
  def self.get_association_hash(arg)
    { :class_name => 'SomeClass', :conditions => ['table.column = ?', arg] }
  end
  has_many :related_things, get_association_hash(arg1)
  has_many :other_things, get_association_hash(arg2)
end

这可能有点难看,并且会弄乱通常的定义顺序。如果是这种情况,那么您可以将您的get_association_hash方法推送到一个模块中,然后将该模块包含在您的类的顶部:

module Pancakes
  def self.included(base)
    # There are various different ways to do this, use whichever one you like best
    base.class_exec do
      def self.get_association_hash(arg)
        # ...
      end
    end
  end
end

class ExampleClass < ActiveRecord::Base
  include Pancakes
  has_many :related_things, get_association_hash(arg1)
  has_many :other_things, get_association_hash(arg2)
end

您可能会将您的模块称为比 更明智Pancakes的名称,这只是我对事物的默认名称(因为foo一段时间后会变得无聊,而且我更喜欢Fargo而不是传统)。

于 2013-06-17T00:52:53.433 回答