扩展ActiveRecord :: Base的正确方法

时间:2010-12-21 16:22:11

标签: ruby-on-rails activerecord observer-pattern extending

我已按以下方式扩展ActiveRecord::Base类:

  • 我在lib下创建了一个目录,我们现在就调用它foo
  • 编写了一个模块,该模块提供了额外的方法has_many_bidirectional,以便在ActiveRecord::Base类中具有双向has_many关系
  • {li}

    lib/foo/active_record.rb

    module Foo
      module ActiveRecord
        autoload :Associations, 'active_record/associations'
        autoload :Base, 'active_record/base'
      end
    end
    
    {li}

    lib/foo/active_record/base.rb

    module Foo
      module ActiveRecord
        module Base
          def self.included(base)
            base.class_eval do
              include Associations
            end
          end
        end
      end
    end
    
  • 当然还有lib/foo/active_record/associations.rb中的真实代码:

    module Foo
      module ActiveRecord
        module Associations
    
          def self.included(base)
            base.extend(ClassMethods)
          end
    
          module ClassMethods
            def has_many_bidirectional(...)
              # ...
            end
          end
        end
      end
    end
    
  • 使用以下代码在ActiveRecord::Base中扩展config/environment.rb类:

    ActiveRecord::Base.class_eval do
      include Foo::ActiveRecord::Base
    end
    
  • 用这种方式将Rails正确地包含在我的模块中,我可以毫无问题地使用它

  • 直到我想观察扩展类,因为在config/environment.rb config.active_record.observers部分之前扩展部分,以及可观察的部分class当时对新方法一无所知。

产生以下错误:

/Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:1998:in `method_missing': undefined method `has_many_bidirectional' for #<Class:0x1032f2fc0> (NoMethodError)
        from .../app/models/user.rb:27

我的问题是,哪种扩展ActiveRecord::Base类的正确方法? (我不想在我的User类中使用回调方法。)

我是否真的必须在lib目录下创建 gem 而不是模块才能拥有此功能?

谢谢!

1 个答案:

答案 0 :(得分:2)

当我把它挖出来时,最好的方法是使用生成器创建一个插件:

./script/generate plugin has_many_bidirectional

通过这种方式,Rails将在观察者部分之前包含它。可以找到一个很好的教程here

我以前的所有代码都可以通过这种方式轻松采用。