правильный способ расширения ActiveRecord :: Base - PullRequest
4 голосов
/ 21 декабря 2010

Я расширил класс ActiveRecord::Base следующим образом:

  • Я сделал каталог под lib, назовем его сейчас foo
  • написал модуль, который предоставляет дополнительный метод has_many_bidirectional для двунаправленных связей has_many в ActiveRecord::Base классах
  • в lib/foo/active_record.rb:

    module Foo
      module ActiveRecord
        autoload :Associations, 'active_record/associations'
        autoload :Base, 'active_record/base'
      end
    end
    
  • в 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 равна до расширяющей части, и наблюдаемый класс ничего не знает о новый метод в этой точке.

Произошла следующая ошибка:

/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 классе.)

Нужно ли создавать модуль gem вместо модуля в каталоге lib, чтобы иметь эту функцию?

Спасибо!

1 Ответ

2 голосов
/ 23 декабря 2010

Как я выяснил, лучший способ - создать плагин с генератором:

./script/generate plugin has_many_bidirectional

И таким образом Rails включит его перед частью наблюдателя.Хороший учебник можно найти здесь .

Весь мой предыдущий код может быть легко адаптирован для этого.

...