#ruby-on-rails-3 #rails-routing #rails-engines
#ruby-on-rails-3 #рельсы-маршрутизация #рельсы-движки
Вопрос:
У меня есть хук before_filter в контроллере приложений моего основного приложения, который выполняет что-то вроде: (Он не просто помещает ссылку во флэш-память, есть сообщение, но оно не имеет отношения к вопросу, оно просто обращается к маршруту в методе)
class ApplicationController < ActionController::Base
before_filter :set_link
def set_link
flash[:notice] = items_path
end
end
Это отлично работает для приложения, однако, когда я захожу в контроллеры для созданного мной движка, я получаю исключение
No route matches {:controller=>"items", :action=>"index"}
Я понимаю, что в движке помощники маршрутов предназначены для движка, если не указано с префиксом main_app
Итак, меняем метод в контроллере приложения на
def set_link
flash[:notice] = main_app.items_path
end
Избавляется от исключения, но я действительно не хочу этого делать. Есть ли другое решение для того, чтобы заставить движок распознавать маршруты main_app?
Редактировать:
Это также происходит, если макет приложения вызывает помощников пути. Итак, если движок предназначен для интеграции в макет main_app, тогда эта проблема тоже возникнет.
Комментарии:
1. Что не так с
main_app
? Кроме того, почему вы вводите зависимость в свой движок от основного приложения, таким образом, ваш движок зависит отitems_path
определения в каждом приложении, которое его использует. Это не очень хорошая практика, обычно вы должны использовать толькоmain_app.root_path
, или некоторые другие хорошо известные маршруты (например, если вы используете devise thesign_in_path
).2. items_path будет определен в основном приложении, которое уже создано. И я хочу, чтобы движок был где-то смонтирован, но интегрирован в макет текущего приложения. Сам движок вообще никогда не ссылается на items_path . Я просто хочу, чтобы представления, сгенерированные движком, помещались в тело макета приложения. Тем не менее, макет приложения должен иметь доступ к маршрутам main_app
3. Это связано с необходимостью иметь общий макет движка и приложения. Таким образом, когда пользователь переходит со страницы основного приложения на страницу движка, видимой разницы между макетом нет.
Ответ №1:
Монтируемые движки предназначены для такой работы, то есть изолируют основные маршруты приложений и маршруты движка.
Если вы хотите, чтобы два набора маршрутов были объединены, вы можете использовать неизолированный движок. Первым шагом является удаление isolated_namespace
вызова метода в определении вашего движка:
module MyEngine
class Engine < Rails::Engine
isolate_namespace MyEngine # remove this line
end
end
Второй шаг — преобразовать ваши маршруты в my_engine/config/routes.rb
, вы должны исходить из этого:
MyEngine::Engine.routes.draw do
# stuff that routes things
end
к этому:
Rails.application.routes.draw do
# stuff that routes things
end
и удалите mount
вызов метода в маршрутах вашего приложения:
App::Application.routes.draw do
mount MyEngine::Engine => "/engine" # remove this line
end
Основными преимуществами этого способа были бы:
-
Нет необходимости исправлять рельсы. Я знаю, что devise делает это, но это может быть пережитком тех дней, когда движков в rails не существовало.
-
Нет необходимости монтировать движок в маршрутах приложений. С другой стороны, это может иметь неприятные последствия, если вы хотите более точно контролировать точку вставки, поскольку все ваши маршруты движка будут вызываться после (или до, у меня нет ответа на этот вопрос) ваших основных маршрутов.
Если вы ищете документацию по движкам, документы rails для класса Engine являются довольно хорошей отправной точкой. Я настоятельно рекомендую вам прочитать их (на случай, если вы еще этого не сделали), если вас интересует эта тема.
Комментарии:
1. вы забыли отметить, что при удалении
isolated_namespace
вы можете столкнуться с некоторыми конфликтами имен с основным приложением или другими драгоценными камнями (пример: помощники)
Ответ №2:
Я понял, как это сделать. Проблемы заключаются в изолированном пространстве имен. Для того, чтобы интегрировать движок с приложением и использовать один и тот же макет (который может иметь помощников пути из основного приложения) Я сделал это:
Сначала я удалил config/routes.rb
из движка
Затем я удалил пространство isolate_namespace из класса engine
module MyEngine
class Engine < Rails::Engine
- isolate_namespace MyEngine
end
end
end
Я добавил файл, который был загружен в движок:
module ActionDispatch::Routing
class Mapper
def mount_my_engine_at(mount_location)
scope mount_location do
#Declare all your routes here
end
end
end
end
Наконец, в основном приложении config/routes.rb
вместо «монтирования» движка вы можете вызвать свой метод
mount_my_engine_at "mount_location"
Это в основном «смонтирует» ваш движок как часть основного приложения, а не изолирует его от него. Это похоже на то, как Devise делает это тоже.
Ответ №3:
Вы можете сохранить пространство isolate_namespace. В вашем движке routes.rb
MyEngine::Engine.routes.draw do
...
root to: "something#index"
end
Rails.application.routes.draw do
get "something", to: "my_engine/something#index"
end
А затем в главном приложении routes.rb
Rails.application.routes.draw do
mount MyEngine::Engine => "/anything_you_want"
root to: "main#index"
end
Таким образом, вы можете выбрать, какие маршруты вы хотите предоставить (а какие нет)
Ответ №4:
Вы можете сохранить пространство isolate_namespace, как настоятельно рекомендуется руководством Rails Engine, и сделать это:
# inside your main_app's config/routes.rb
Rails.application.routes.draw do
root to: 'home#index'
mount MyEngine::Engine, at: "/"
end
# inside your engine's controller
module MyEngine
class SomeController << ::ApplicationController
# include main_app's route helpers
helper Rails.application.routes.url_helpers
end
end
И внутри вашего драгоценного камня убедитесь, что все помощники URL имеют префикс правильного метода прокси-сервера маршрутизации (например, my_engine.pages_path).
Макет вашего main_app и контроллер движка будут правильно маршрутизировать и ссылаться на эти помощники url в основном приложении. Вам не нужно нигде добавлять префикс «main_app» к основному приложению. Единственным недостатком является то, что вы монтируете маршруты своего движка по корневому пути main_app, что может столкнуться с любыми маршрутами с тем же именем. Это ожидается в любом случае, если вы должны были использовать не-isolate_namespace.
Ответ №5:
Самый простой способ — нарисовать маршруты как в основном приложении, так и в движке, чтобы они были доступны для обоих:
[MyEngine::Engine, App::Application].each do |app|
app.routes.draw do
# Declare all your routes here
end
end