Rails引擎扩展function

我有一个引擎定义了一些模型和控制器。 我希望能够在我的应用程序中扩展某些模型/控制器的function(例如添加方法),而不会从引擎中丢失原始模型/控制器function。 在我读到的任何地方,您只需要在应用程序中定义具有相同名称的控制器,Rails将自动合并它们,但它对我不起作用,引擎中的控制器被简单地忽略(我不认为它甚至被加载)。

require MyEngine::Engine.root.join('app', 'models', 'my_engine', 'my_model') 

在应用程序中的模型类定义之前。

您可以将这些行添加到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的默认function,并且还有一个简单的工具来使用普通的rubyinheritance,而不需要修补。

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" 

如果其他人在将来的某个时间遇到同样的问题,这就是我编写的修复我的问题的代码:

 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”开头,这将自动要求应用程序中的文件。

那是真实的。 将使用首先找到的控制器。

因此,要使其工作,您可能有两个选择:

  • 创建控制器的本地副本,并修改所需的方法
  • 如果你可以控制插件,你可以创建一个包含代码的模块,并在两个控制器中包含代码,只覆盖本地控制器中的方法。 据我所知,由于没有多重inheritance,这是唯一的方法。

希望这可以帮助。

您可以更改引擎的加载顺序,以避免每个模型的要求。

在config / application.rb中添加以下行:

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

这将确保在MyApp之前加载MyEngine中的模型

我之前从未使用过Engines,但是你不能定义一个inheritance自引擎提供的控制器的新控制器