Маршруты движка в контроллере приложения

#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 the sign_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
  

Основными преимуществами этого способа были бы:

  1. Нет необходимости исправлять рельсы. Я знаю, что devise делает это, но это может быть пережитком тех дней, когда движков в rails не существовало.

  2. Нет необходимости монтировать движок в маршрутах приложений. С другой стороны, это может иметь неприятные последствия, если вы хотите более точно контролировать точку вставки, поскольку все ваши маршруты движка будут вызываться после (или до, у меня нет ответа на этот вопрос) ваших основных маршрутов.

Если вы ищете документацию по движкам, документы 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