0

我在 attribute_fu 插件中看到以下代码:

module AttributeFu
    module Associations #:nodoc:                                                                                                                                                
        def self.included(base) #:nodoc:                                                                                                                                          
            base.class_eval do
                extend ClassMethods
                class << self; alias_method_chain :has_many, :association_option; end

                class_inheritable_accessor  :managed_association_attributes
                write_inheritable_attribute :managed_association_attributes, []

                after_update :save_managed_associations
            end
        end

        ...
    end
end

当我尝试更换

class << self; alias_method_chain :has_many, :association_option; end

与:别名方法链:has_many,:association_option?

我收到以下错误

/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/module/aliasing.rb:31:in `alias_method': undefined method `has_many' for class `ActiveRecord::Base' (NameError)
        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/module/aliasing.rb:31:in `alias_method_chain'
        from /home/twong/git/physpace/vendor/plugins/attribute_fu/lib/attribute_fu/associations.rb:9:in `included'

我认为这两行会做同样的事情,但看起来我错了。有人可以解释我的错误吗?

4

2 回答 2

3
# init.rb
ActiveRecord::Base.class_eval { include AttributeFu::Associations }

module AttributeFu
    module Associations
        def self.included(base)
            # base == ActiveRecord::Base (the class)
            base.class_eval do
                # class_eval makes self == ActiveRecord::Base, and makes def define instance methods.
                extend ClassMethods

                # If has_many were an instance method, we could do this
                #   alias_method_chain :has_many, :association_option; end
                # but it's a class method, so we have to do the alias_method_chain on
                # the meta-class for ActiveRecord::Base, which is what class << self does.
                class << self; alias_method_chain :has_many, :association_option; end
            end
        end
    end
end

另一种解决方法是将其放入 IRB:

class A ; end
A.class_eval { puts self.inspect ; class << self ; puts self.inspect ; end }

也可以看看

于 2008-12-05T19:27:03.127 回答
0

在那种情况下,self并不意味着 anObject,它更像是一个糖构造。

class << self
  ...
end

定义封闭对象的类方法。方法alias_method_chain是一种方法,即给事物起别名。在这种情况下,它别名has_manyhas_many_without_association_optionshas_many_with_association_optionswith has_many。在您的情况下,它是类方法的别名,因此,您必须在类方法范围内使用它。它允许扩展方法而没有太多麻烦。

类方法被称为,比如:

SomeThing.bar_method

而实例方法在类的实例上调用:

assoc = SomeThing.new
assoc.foo_method

相应的代码是:

class SomeThing
  def foo_method
    ...
  end
  class << self
    def bar_method
      ...
    end
  end
end

在你的情况下,你有模块AttributeFu::Associations。当包含在类 Foo 中时,它运行 Foo.class_eval,它在 Foo 中定义了一些实例属性,并alias_method_chain在类方法范围 ( class << self) 内启动一个方法。

还有一个extends ClassMethods必须定义:

def self.has_many_with_association_options
    ...
end

或者

class << self
  def has_many_with_association_options
    ...
  end
end
于 2008-12-04T22:34:22.283 回答