Building Frontend & Backend in One Rails App
May be you know it. Frontend and backend/administration. Two completely different looks, but one application. Two different sets of stylesheets and javascripts, but one set of models, validations etc.
Most of my apps have some kind of administration, which is separated from the normal users’ part. When I started with Rails, understanding assets was a challenge I was battling hard. But separating frontend and administration parts was even higher level for me!
The tricky part is in routes and setting up the assets in a right way.
Controllers
I like to keep things clear, so to keep those two parts separated I generate them into subfolders:
> rails g controller frontend/home index
> rails g controller admin/dashboard index
Files generated are as you expect:
/app/controllers/frontend/home_controller.rb
class Frontend::HomeController < ApplicationController
def index
end
end/app/controllers/admin/dashboard_controller.rb
class Admin::DashboardController < ApplicationController
def index
end
end
But I want each of my controllers having a specific layout, of course. The easiest way to achieve this is to create a parent controllers, set them a layout (I will create those layouts later, don’t worry) and inherit from them (I don’t generate these parent controllers as I don’t want any tests and fixtures to be created, I just create new files manually):
/app/controllers/frontend_controller.rb
class FrontendController < ApplicationController
layout 'frontend/application'
end/app/controllers/admin_controller.rb
class AdminController < ApplicationController
layout 'admin/application'
end
Now to inherit HomeController
and DashboardController
from those parents just update them as following:
/app/controllers/frontend/home_controller.rb
class Frontend::HomeController < FrontendController
def index
end
end/app/controllers/admin/dashboard_controller.rb
class Admin::DashboardController < AdminController
def index
end
end
Routes
Routes seems to be easy, but there is one small hitch. I want my admin part to be running under the localhost:3000/admin
folder, but the frontend should be running on the root:
/config/routes.rb
Rails.application.routes.draw do namespace :admin do
resource :dashboard, only: :index
root to: 'dashboard#index'
end scope module: 'frontend' do
resources :home, only: :index
root to: 'home#index'
endend
At first I set the namespace for /admin
part of the url by namespace :admin do
. On the next row I set standard resource for dashboard, but constraint it just to index
action. As the last for the admin I set root for the admin part, so /admin
is mapped to /admin/dashboard/index
.
As I have written above I don’t want the frontend to be mapped to any subfolder, so I’m telling to Rails I’m gonna using controller in a frontend module (remember Frontend::HomeController
in the controller above?), but by scope module...
I’m not mapping it to any subfolder in url.
The rest is the same as it was for the admin.
Assets
Now the core part — assets. Under the javascript and stylesheets assets folders there should be frontend
and admin
subfolders already created (they were created when I generated the controllers). If not, create them.
Let’s do same renaming and copying here now:
Move/Copy/app/assets/javascripts/application.js
to:
/app/assets/javascripts/frontend.js
/app/assets/javascripts/admin.js
And the same for stylesheets:
/app/assets/stylesheets/application.css
to:
/app/assets/stylesheets/frontend.css
/app/assets/stylesheets/admin.css
In these files you import stylesheets and javascripts the same way you are used to, but use each of these files for importing of proper frontend/admin related files.
It should look now like this (among other files and folders, I’m showing here only the important files):
/app/assets/images
- admin
- frontend/app/assets/javascripts
- admin
- frontent
- admin.js
- frontend.js/app/assets/stylesheets
- admin
- frontend
- admin.css
- frontend.css
Rails must know about these new asset files to be able to compile them. Add this 4 lines to the end of assets config file:
/config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( admin.css )
Rails.application.config.assets.precompile += %w( admin.js )
Rails.application.config.assets.precompile += %w( frontend.css )
Rails.application.config.assets.precompile += %w( frontend.js )
Layouts
And at the end I’m returning back to the start (as I promised in the controllers part) — I have to setup layouts. In /app/views/layouts
I create two folders: frontend
and admin
. I copy application.html.erb
to both of them (you can delete this file from its origin location). Now I must set stylesheets and javascript include tags in each layout to be pointing to the assets in the proper subfolder (remember the frontend
and admin
subfolders in /app/assets/images
, /app/assets/javascripts
and /app/assets/stylesheets
?):
/app/views/layouts/frontend/application.html.erb
# change the first parameter from 'application' to 'frontend':
<%= stylesheet_link_tag 'frontend', media: 'all', 'data-turbolinks-track': 'reload' %># same for javascripts:
<%= javascript_include_tag 'frontend', 'data-turbolinks-track': 'reload' %>/app/views/layouts/admin/application.html.erb
# change the first parameter from 'application' to 'admin':
<%= stylesheet_link_tag 'admin', media: 'all', 'data-turbolinks-track': 'reload' %># same for javascripts:
<%= javascript_include_tag 'admin', 'data-turbolinks-track': 'reload' %>
Conclusion
And that’s it! Not that hard when you know what to do ;)
Questions?
Into comments, I will answer.
○ I’m still brand new with my CodeRocket. If you like what I’m doing, help me to get to a broader audience by clicking ❤ below. I will appreciate it!
And follow me to see what I’m working on! ○