Motores Rails que amplían la funcionalidad

Tengo un motor que define algunos modelos y controladores. Quiero poder ampliar la funcionalidad de algunos modelos / controladores en mi aplicación (por ejemplo, agregar métodos) sin perder la funcionalidad del modelo / controlador original del motor. Dondequiera que lea, simplemente necesita definir el controlador con el mismo nombre en su aplicación y Rails los fusionará automáticamente, sin embargo, no funciona para mí y el controlador en el motor simplemente se ignora (no creo que esté siquiera cargado).

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

antes de la definición de clase de modelo en su aplicación.

Puede agregar estas líneas al archivo del módulo del motor en el directorio raíz de 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 

Luego tiene la capacidad en la aplicación principal (la aplicación que hace uso del motor) para requerir los archivos necesarios del motor. Esto es bueno porque mantiene la funcionalidad predeterminada de Rails Engines y también tiene una herramienta fácil para hacer uso de la herencia de Ruby normal, sin la necesidad de parches.

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" 

Solo si alguien más se encuentra con el mismo problema en algún momento en el futuro, este es el código que escribí que solucionó mi problema:

 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 

Esto requerirá automáticamente archivos del motor antes de requerir de la aplicación si la ruta del archivo comienza con ‘app’.

Eso es verdad. El controlador que se encuentra primero se usará.

Para que funcione, es posible que tenga dos opciones:

  • crea una copia local del controlador y modifica el método que necesitas
  • si tiene control sobre el complemento, puede crear un Módulo que contenga el código e incluir el código en ambos controladores, solo anulando el método en su controlador local. Según yo, dado que no hay herencia múltiple, esa es la única forma.

Espero que esto ayude.

Puede cambiar el orden de carga del motor para evitar el requerimiento en cada uno de sus modelos.

En config / application.rb agregue esta línea:

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

Esto asegurará que los modelos de MyEngine se carguen antes de MyApp

Nunca antes he usado motores, pero no se puede definir un nuevo controlador que herede del controlador proporcionado por el motor