Подтвердить что ты не робот

Render engine в макете приложения

Фон

Я создаю приложение, состоящее из ядра и нескольких модулей. Модули являются рельсовыми двигателями и обеспечивают фактическую функциональность, поскольку сам ядро ​​действует только как хост. Двигатели размещаются с /lib и монтируются по их соответствующим путям.

coreApp
└──lib
   ├── module1
   ├── module2
   └── etc

Затем модули монтируются таким образом

mount Module1::Engine => "/module1", :as => "module1"
mount Module2::Engine => "/module2", :as => "module2"

Ядро также отвечает за обработку сеанса, хотя сам вход выполняется с помощью модуля.

Проблема

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

coreApp
└── app
    └── views
        └── layouts
            ├── application.html.erb
            └── core.html.erb

Файл core.html.erb содержит только

<%= render :template => 'layouts/application' %>

Затем он включается в каждый модуль, подобный этому

module Module1
  class ApplicationController < ActionController::Base
    layout "core"
  end
end

Хотя он не особенно изящный, он отлично работает, и содержимое модуля отображается там, где оператор yield в макете приложения.

Проблемы заключаются в следующем:

1. Таблицы стилей, специфичные для модуля, не включены в заголовок

Мне нужен способ включить таблицы стилей активного модуля.

2. Заголовок нуждается в доступе к информации о зарегистрированном пользователе

Заголовок содержит информацию о зарегистрированном пользователе, например

Logged in as <%= @user[:realname] %>

Это происходит от ядер home_controller

def index
  @user = User.find_by_id(session[:user])
end

Но когда я пытаюсь получить доступ к модулю, я получаю следующую ошибку

NoMethodError in Module1/home#index

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]

Очевидно, ссылаясь на @user.

Вопрос

Как это можно решить как изящно и сухим, насколько это возможно, без чрезмерного вмешательства на стороне двигателя?

У меня есть многого, но я не могу понять, как это решить. Это может быть полное отсутствие понимания того, как работают рельсы, поэтому есть хороший шанс, что этот вопрос даже не имеет смысла для тех, кто хорошо знает рельсы.

Прокомментируйте, если что-то неясно или неоднозначно, и я попытаюсь уточнить.

4b9b3361

Ответ 1

Я успешно использовал макеты моего родительского приложения в своих машинах. Во-первых, на основе Раздела 4.3.2 Rails Guides (Engines), чтобы получить доступ к родительским приложениям. Параметры ApplicationController (например, session, поскольку вы используете выше), вам необходимо заменить двигатель application_controller.rb на тот, который у вас есть:

module Module1
  class ApplicationController < ActionController::Base
    layout "core"
  end
end

:

class Module1::ApplicationController < ::ApplicationController
end

Это наследует родительское приложение ApplicationController и все его переменные.

Во-вторых, вам нужно будет удалить файл app/views/layouts/application.html.erb из представлений вашего механизма, поскольку он не понадобится, поскольку вы используете родительское приложение.

Теперь, когда вы визуализируете представление Module1 из родительского приложения, будет использоваться макет родительского приложения, и все переменные session[] будут оценены правильно.

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

Надеюсь, что это поможет.

Ответ 2

Используйте layout 'layouts/application'

И если вы не хотите использовать main_app.your_path, вы также можете добавить:

module YourEngine
  module ApplicationHelper
    def method_missing(method, *args, &block)
      if (method.to_s.end_with?('_path') || method.to_s.end_with?('_url')) && main_app.respond_to?(method)
        main_app.send(method, *args)
      else
        super
      end
    end
  end
end

Ответ 3

Я также сделал то же самое в своем приложении. Все, что я сделал, это:

  • Удалить макет двигателя в /app/view/layouts/
  • Измените приложение application_controller на

    module EngineModule
      class ApplicationController < ::ApplicationController
        layout 'layouts/application' 
      end
    end
    
  • В ваших представлениях, если вы хотите обратиться к любому пути, например, login_path, его можно передать через main_app.login_path