Rails двигатели расширяют функциональность - PullRequest
15 голосов
/ 03 июня 2010

У меня есть двигатель, который определяет некоторые модели и контроллеры. Я хочу иметь возможность расширять функциональность некоторых моделей / контроллеров в моем приложении (например, добавление методов) без потери исходной функциональности модели / контроллера из движка. Везде, где я читал, вам просто нужно определить контроллер с тем же именем в вашем приложении, и Rails автоматически объединит их, однако это не работает для меня, и контроллер в движке просто игнорируется (я не думаю, что он даже загружен).

Ответы [ 6 ]

18 голосов
/ 15 марта 2011
require MyEngine::Engine.root.join('app', 'models', 'my_engine', 'my_model')

до определения класса модели в вашем приложении.

8 голосов
/ 23 февраля 2011

Вы можете добавить эти строки в файл модуля вашего движка в корневом каталоге lib:

def self.root
  File.expand_path(File.dirname(File.dirname(__FILE__)))
end

def self.models_dir
  "#{root}/app/models"
end

def self.controllers_dir
  "#{root}/app/controllers"
end

Тогда у вас есть возможность в главном приложении (приложение, использующее движок) запрашивать необходимые файлы из движка. Это хорошо, потому что вы поддерживаете стандартную функциональность Rails Engines, а также имеете простой инструмент для использования обычного наследования ruby ​​без необходимости исправлений.

EX:

#ENGINE Model -

class User < ActiveRecord::Base
  def testing_engine
    puts "Engine Method"  
  end
end

#MAIN APP Model -

require "#{MyEngine.models_dir}/user"
class User
  def testing_main_app
    puts "Main App Method"  
  end
end

#From the Main apps console

user = User.new

puts user.testing_engine #=>  "Engine Method"

puts user.tesing_main_app #=> "Main App Method"
2 голосов
/ 07 июня 2010

Просто если кто-нибудь еще столкнется с той же проблемой в будущем, это код, который я написал, который исправил мою проблему:

module ActiveSupport::Dependencies
  alias_method :require_or_load_without_multiple, :require_or_load
  def require_or_load(file_name, const_path = nil)
    if file_name.starts_with?(RAILS_ROOT + '/app')
      relative_name = file_name.gsub(RAILS_ROOT, '')
      @engine_paths ||= Rails::Initializer.new(Rails.configuration).plugin_loader.engines.collect {|plugin| plugin.directory }
      @engine_paths.each do |path|
        engine_file = File.join(path, relative_name)
        require_or_load_without_multiple(engine_file, const_path) if File.file?(engine_file)
      end
    end
    require_or_load_without_multiple(file_name, const_path)
  end
end

Для этого автоматически потребуются файлы из движка, а затем из приложения, если путь к файлу начинается с «app».

1 голос
/ 05 февраля 2015

Вы можете изменить порядок загрузки двигателя, чтобы избежать потребности на каждой из ваших моделей.

В config / application.rb добавьте эту строку:

module MyApp
  class Application
    config.railties_order = [MyEngine::Engine, :main_app, :all]
  end
end

Это обеспечит загрузку моделей из MyEngine до MyApp

.
1 голос
/ 03 июня 2010

Это правда. Будет использован контроллер, который был найден первым.

Таким образом, чтобы это работало, у вас может быть два варианта:

  • создайте локальную копию контроллера и измените нужный метод
  • если у вас есть контроль над плагином, вы можете создать Модуль, содержащий код и включить код в обоих контроллерах, только переопределяя метод в вашем локальном контроллере. По моему мнению, поскольку множественного наследования не существует, это единственный путь.

Надеюсь, это поможет.

0 голосов
/ 03 июня 2010

Я никогда раньше не использовал Двигатели, но вы не можете определить новый контроллер, который наследуется от контроллера, предоставленного движком

...