Ответ 1
То, что вы пытаетесь сделать, довольно сложно. Как уже упоминалось, маршруты двигателей загружаются после того, как маршруты приложений и переопределение этого поведения могут быть проблематичными. Я могу придумать несколько вещей, которые вы можете попробовать.
Использовать инициализатор после инициализации путей маршрутизации
В источнике rails есть инициализатор в engine.rb
, один из способов выполнить то, что вам нужно, - попытаться подключиться к функциональности, с которой он имеет дело. Инициализатор по умолчанию выглядит так:
initializer :add_routing_paths do |app|
paths.config.routes.to_a.each do |route|
app.routes_reloader.paths.unshift(route) if File.exists?(route)
end
end
По существу, это должно идти по пути ко всем файлам маршрутов, о которых знает Rails, и пытаться их добавить в перегружатель маршрутов (то, что автоматически перезагружает файл маршрутов для вас, если оно изменено). Вы можете определить другой инициализатор, который будет запущен сразу после этого, затем вы проверите пути, хранящиеся в перегружателе маршрутов, вытащите путь, принадлежащий вашему движку, удалите его из массива путей и вставьте его обратно, но в конце массива путей. Итак, в config/application.rb
:
class Application < Rails::Application
initializer :munge_routing_paths, :after => :add_routing_paths do |app|
engine_routes_path = app.routes_reloader.paths.select{|path| path =~ /<regex that matches path to my engine>/}.first
app.routes_reloader.paths.delete(engine_routes_path)
app.routes_reloader.paths << engine_routes_path
end
end
Это может быть или не работать, в любом случае, я не рекомендую его, он не особенно изящный (например, уродливый хак, играющий с кишками рельсов).
Использовать Rails 3.1
Это может быть не вариант, но если это так, я, вероятно, поеду с этим. В Rails 3.1 у вас может быть 2 разных типа двигателей, полный и монтируемый (здесь вопрос SO, говорящий о некоторых различиях). Но по существу вы изменили бы ваш движок на монтируемый движок, маршруты в монтируемом двигателе будут заменены на имена, и вы можете явно включить их в файл маршрутов вашего основного приложения, например:
Rails.application.routes.draw do
mount MyEngine::Engine => "/news"
end
Вы также можете использовать свои смонтированные маршруты двигателей и делать всевозможные другие причудливые вещи (подробнее здесь). Короче говоря, если вы можете перейти к 3.1, то это подход к использованию.
Динамическая вставка маршрутов из вашего движка в основное приложение
В настоящее время одним из самых известных двигателей Rails является Devise. Теперь, devise - это движок, который потенциально добавит довольно много маршрутов в ваше приложение, но если вы посмотрите на источник разработки, вы увидите, что на самом деле у него нет файла config/routes.rb
! Это связано с тем, что приложение динамически добавляет свою правку маршрутизации в основной файл приложения routes.rb
.
Когда вы запустите генератор модели, который поставляется с программой, одна из вещей, которую сделает генератор, это добавить строку, такую как devise_for :model
вверху вашего файла route.rb, сразу после строки Rails.application.routes.draw do
. Таким образом, ваш route.rb выглядит аналогично этому после того, как вы выполните генератор для создания модели User:
Rails.application.routes.draw do
devise_for :users
...
end
Теперь, devise_for - магический метод, который приходит как часть разработки (в lib/devise/rails/routes.rb
), но по существу он создаст кучу регулярных маршрутов, которые все мы знаем на основе созданной вами модели.
То, что нам нужно знать, - это то, как разработчик вставляет эту строку в файл приложений routes.rb
, тогда мы можем написать генератор в нашем движке, который вставляет любой из наших маршрутов в верхней части основных приложений routes.rb
файл. Для этого рассмотрим lib/generators/devise/devise_generator.rb
. В методе add_devise_routes
последняя строка route devise_route
. Route
- это действие Thor, которое вставляет строку, переданную в основное приложение routes.rb
. Поэтому мы можем написать собственный генератор и сделать что-то подобное, например:
class MyCrazyGenerator < Rails::Generators::NamedBase
...
def add_my_crazy_routes
my_route = "match '/news', :to => 'bar_controller#foo_action'"
route my_route
end
end
Конечно, вам нужно будет убедиться, что вся инфраструктура генератора находится на своем месте, но суть. Разработчик написан некоторыми очень умными рельсовыми чуваками и используется довольно многими людьми, имитируя то, что они делают, вероятно, довольно хороший путь. Из 3 вещей, которые я предложил, это было бы так, как я бы справился с вашей проблемой (учитывая, что переход к рельсам 3.1, вероятно, не вариант).