Расширение функциональности Rails
У меня есть двигатель, который определяет некоторые модели и контроллеры. Я хочу иметь возможность расширять функциональность некоторых моделей/контроллеров в моем приложении (например, методы добавления), не теряя исходных функций модели/контроллера с движка. Всюду я читал, что вам просто нужно определить контроллер с тем же именем в вашем приложении, и Rails автоматически объединит их, однако он не работает для меня, а контроллер в движке просто игнорируется (я не думаю, что он даже загружен).
Ответы
Ответ 1
Просто, если кто-то еще столкнется с тем же вопросом в будущем, это код, который я написал, который исправил мою проблему:
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
Это автоматически потребует файлы от двигателя, прежде чем требовать от приложения, если путь к файлу начинается с "приложения".
Ответ 2
require MyEngine::Engine.root.join('app', 'models', 'my_engine', 'my_model')
до определения класса модели в вашем приложении.
Ответ 3
Вы можете добавить эти строки к вашему файлу модуля двигателя в корневой каталог 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 без необходимости исправления.
Пример:
#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"
Ответ 4
Это верно. Контроллер, который будет найден первым, будет использоваться.
Итак, чтобы заставить его работать, у вас может быть два варианта:
- создать локальную копию контроллера и изменить метод, который вам нужен.
- Если у вас есть контроль над плагином, вы можете создать модуль, содержащий код, и include код в обоих контроллерах, только переопределяя метод в локальном контроллере.
По мне, поскольку нет множественного наследования, это единственный способ.
Надеюсь, что это поможет.
Ответ 5
Вы можете изменить порядок загрузки двигателя, чтобы избежать необходимости на каждой из ваших моделей.
В config/application.rb добавьте эту строку:
module MyApp
class Application
config.railties_order = [MyEngine::Engine, :main_app, :all]
end
end
Это обеспечит загрузку моделей из MyEngine до MyApp
Ответ 6
Я никогда раньше не использовал Двигатели, но не могу определить новый контроллер, который наследуется от контроллера, предоставленного двигателем