I am creating a application that is made up of a core and several modules. The modules are rails engines, and provide the actual functionality as the core itself only acts as a host. The engines are hosted from /lib
and mounted at their respective paths.
coreApp └──lib ├── module1 ├── module2 └── etc
The modules are then mounted like this
mount Module1::Engine => "/module1", :as => "module1" mount Module2::Engine => "/module2", :as => "module2"
The core is also responsible for handeling the session, although the login itself is done by a module.
I have yet to find a great way of sharing the core application layout with the engines. As of now, this is how I make the layout available to the engines:
coreApp └── app └── views └── layouts ├── application.html.erb └── core.html.erb
The file core.html.erb
only contains
<%= render :template => 'layouts/application' %>
Is is then included in each module like this
module Module1 class ApplicationController < ActionController::Base layout "core" end end
Although it isn't particularly elegant, it works fine, and the content of the module is rendered where the yield
statement in the application layout.
The problems are as follows:
I need a way to include the stylesheets of the active module.
The header contains information about the logged in user, like
Logged in as <%= @user[:realname] %>
This comes from the cores home_controller
def index @user = User.find_by_id(session[:user]) end
But when I try to access the module, I get the following error
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.[]
Obviously referring to @user
.
How can this be solved in as elegantly and DRY as possible without too much tampering on the engine side?
I have Googled this a lot but can't really get my head around how to solve it. It might be total lack of insight in how rails works, so there is a good chance this question doesn't even make sense for someone that knows rails well.
Please comment if anything is unclear or ambiguous, and I'll try to elaborate.
This rendering engine is used by applications built with JSS for Next.js or the Sitecore ASP.NET Rendering SDK. When working with the ASP.NET Rendering SDK, you must perform some configuration to use the Rendering Engine with your application. For details, refer to the using the Rendering Engine with the ASP.NET Rendering SDK.
Rendering engines render content and layout data returned by the Sitecore Layout Service from a Sitecore instance. Within the Sitecore Headless Services module, Sitecore provides two implementations of a rendering engine: The Node.js rendering engine, enabled by default.
Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your BooksController class: And the following in your routes file: And you have a view file app/views/books/index.html.erb:
There are times when you might like to change this, and you can do so by setting the :content_type option: With most of the options to render, the rendered content is displayed as part of the current layout. You'll learn more about layouts and how to use them later in this guide.
I have successfully used layouts of my parent application in my engines. Firstly, based on Section 4.3.2 of the Rails Guides (Engines), in order to access the parent applications ApplicationController's variables (like session
, as you're using above), you need to replace the engine's application_controller.rb
from this that you currently have:
module Module1 class ApplicationController < ActionController::Base layout "core" end end
to this:
class Module1::ApplicationController < ::ApplicationController end
This will inherit the parent application's ApplicationController, along with all it's variables.
Secondly, you'll need to delete the file app/views/layouts/application.html.erb
from your engine views, as it will not be needed since you're using the parent application's one.
Now when you render a view of Module1 from the parent application, the layout of the parent application will be used, and all the session[]
variables will be evaluated correctly.
Do not forget to add the words "main_app." before each link in your layouts, otherwise it will try and look for the paths in the engine instead of the parent application. For example, if the layout in the parent application includes a link to some_path
(that is a view in the parent application), when showing a view in the engine that uses this layout will try and look for some_path
in the Engine instead of the parent application. You will need to change the link to main_app.some_path
for it to work.
Hope this helps.
Use layout 'layouts/application'
And if you don't want to use main_app.your_path you can also add:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With