Using a Model Provided by the Application inside Rails Engine
Sometimes when creating a Engine in Rails, we would like to associate a Model inside the engine with A model in our Main Application.
When an engine is created, it may want to use specific classes from an application to provide links between the pieces of the engine and the pieces of the application.
In the case of the engine in the image above, making articles have authors would make a lot of sense.
A typical application might have a
User class that would be used to represent authors for an article .
But there could be a case where the application calls this class something different, such as
Person. For this reason, the engine should not hardcode associations specifically for a
First Thing we need inside the Engine is a field in the form to get Attributes of Article’s author.
Next, we need to update our
EngineName::ArticleController#article_params method to permit the new form parameter:
params.require(:article).permit(:title, :text, :author_name)
Engine::Article model should then have some code to convert the
author_name field into an actual
User object and associate it as that article's
author before the article is saved. It will also need to have an
attr_accessor set up for this field, so that the setter and getter methods are defined for it.
So we make the necesaary changes in our Articles model models/engine_name/article.rb
belongs_to :author, class_name:EngineName.author_class.to_s
set_author is used to find or create a new entry by name in the User’s table and reference it with the article being created.
By representing the
author association's object with the
User class, a link is established between the engine and the application. There needs to be a way of associating the records in the
engine_name_articles table with the records in the
users table. Because the association is called
author, there should be an
author_id column added to the
To generate this new column, run this command within the engine:
$ bin/rails g migration add_author_id_to_engine_name_articles author_id:integer
To make this author customizable, the engine will have a configuration setting called
author_class that will be used to specify which class represents users inside the application.
To define this configuration setting, you should use a
mattr_accessor inside the engine. Add this line to
lib/engine_name.rb inside the engine:
This provides a setter and getter method on the module with the specified name. To use it, it must be referenced using
We need to add this code below mattr-accessor inside
constantize tries to find a declared constant with the name specified in the string.
Because Rails controllers generally share code for things like authentication and accessing session variables, they inherit from
ApplicationController by default. Rails engines, however are scoped to run independently from the main application, so each engine gets a scoped
ApplicationController. This namespace prevents code collisions, but often engine controllers need to access methods in the main application's
ApplicationController. We would need access methods in the main application to make a link between Article and the User.
app/controllers/engine_name/application_controller.rb to looks like:
ApplicationController < ::ApplicationController
To set this configuration setting within the application, an initializer should be used. By using an initializer, the configuration will be set up before the application starts and calls the engine’s models, which may depend on this configuration setting existing.
Create a new initializer at
config/initializers/engine_name.rb inside the application where the engine is mounted and put this content in it:
EngineName.author_class = "User"
User could be the model inside your application which you want to link with articles.
Now inside you engine you can access your user like this
But what if we wanted to do something like this in our Application
<% @user.project.each do |u| %>
<%= u.title %><br>
<%= u.description %><br>
<% end %>
For this we’ll have to add a has_many association in our Users Model in Main Application. app/models/user.rb
has_many :project, :class_name => EngineName::Article , :foreign_key => :author_id