In the previous article, we've done setting up our Surface module
How to Architect Rails Project - Part 1
In this article, we'll cover the following features:
- Module Admin
- Layouts
- Front-End Scaffolding
So, let's kick off...
For our Admin module, we want to get these routes
'domain.com/admins' # Overview, basic reports, charts
'domain.com/admins/blog' # Articles CRUD
'domain.com/admins/work' # Work CRUD
Let's add them to our routes.
# config/routes.rb
Rails.application.routes.draw do
...
namespace :admins do
resources :blogs
resources :works
end
end
Why admins and not admin in singular? Because this module was thought to have multiple user types, users that only can publish articles and won't have permissions to publish works.
Moving on, we need to create the views for our Admin module according to our routes.
Create these files inside app/views
folder
app/views
├── admins/blogs
│ └── index.html.erb
│ └── show.html.erb
├── admins/works
│ └── index.html.erb
│ └── show.html.erb
└── layouts
└── admin.html.erb
Let's add our markup to admin.html.erb
layout, for now, let's copy the content from application.html.erb
. Our layout would look like this...
<!DOCTYPE html>
<html>
<head>
<title>Portfolio</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= render "partials/header" %>
<%= yield %>
</body>
</html>
Cool right? We have our Admin layout.
Hold on your horses... We are still using the assets from our Surface module (application), we want to isolate Admin/Surface and make them to not depend on each other, so, let's isolate our Admin assets out of the Surface module.
Create these files under app/assets/stylesheets
...
app/assets/stylesheets
├── admin/base
│ └── _base.scss
│ └── _variables.scss
├── admin/components
│ └── _header.scss
│ └── _sidebar.scss
└── admin.scss
So our admin.scss
would look like this...
// Base theming
@import "admin/base/variables";
@import "admin/base/base";
// Components
@import "admin/components/header";
@import "admin/components/sidebar";
Next, add this line to our base_controller.rb
under controller/admins
folder
class Admins::BaseController < ApplicationController
layout 'admin'
end
We need also to tell rails that we want to use admin.css|admin.js
in our initializer, so add the following line to config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( admin.js admin.css )
Now let's change our admin.html.erb
layout to use admin.css
and remove the current header stylesheet which comes from the Surface
module.
<!DOCTYPE html>
<html>
<head>
<title>Portfolio</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'admin', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
Well done! now if we run rails s
and navigate to http://localhost:3000/admins/blogs
we should see a blank page. If we inspect elements in the browser we'll see that our styles are coming from admin and not application anymore.
Alright, Renzo, this is cool but I don't see any component and styles on the page yet. Besides the javascript still comes from the Surface module.
Before deep into the components and styles, let's add an Admin module for our javascript files, this is pretty much the same as what we did with styles.
So, let's create an admin.js
file under app/javascript/packs
folder and add the following lines...
// app/javascript/packs/admin.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
Change <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
to <%= javascript_pack_tag 'admin', 'data-turbolinks-track': 'reload' %>
in our admin.html.erb
layout
<!DOCTYPE html>
<html>
<head>
<title>Portfolio</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'admin', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'admin', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
Let's restart our server and see what we got, we should see the same blank page if we navigate to http://localhost:3000/admins/blogs
. If we inspect the page we'll see that now our javascript comes from admin.
Now we have our js/css isolated from the Surface module, let's add Bulma to our project and start building our components.
Add Bulma gem to our Gemfile
at the bottom
gem "bulma-rails", "~> 0.8.0"
Then run bundle install
in the terminal.
In this article we are going to use Bulma in both modules
Surface/Admin
, just to not make this article too long. Remember that we can also isolate to use Bulma for the Admin and any other framework for our Surface.
Now let's build our layout markup correctly for the Admin module.
<!Doctype html>
<html>
...
<body>
<%= render "patials/admin/header" %>
<div class="columns is-fullheight">
<div class="column is-2 is-sidebar-menu is-hidden-mobile">
<%= render "partials/admin/sidebar" %>
</div>
<div class="column is-main-content">
<%= yield %>
</div>
</div>
</body>
</html>
Create a admin
folder under app/views/partials
add these files...
app/views/partials/admin/_header.html.erb
<nav class="navbar">
<div class="navbar-brand">
<a class="navbar-item" href="#">
Logo
</a>
<div class="navbar-burger burger" data-target="navMenubd-example">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navMenubd-example" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
<figure class="avatar image is-32x32">
<img class="is-rounded" src="https://bulma.io/images/placeholders/32x32.png" alt=""/>
</figure>
username
</a>
<div class="navbar-dropdown is-right">
<a class="navbar-item">
Logout
</a>
</div>
</div>
</div>
</div>
</nav>
app/views/partials/admin/_sidebar.html.erb
<aside class="menu">
<p class="menu-label">
General
</p>
<ul class="menu-list">
<li><%= link_to 'Overview', admins_blogs_path %></li>
</ul>
<p class="menu-label">
Administration
</p>
<ul class="menu-list">
<li>
<%= link_to 'My Work', admins_works_path %>
</li>
<li><%= link_to 'My Work', admins_blogs_path %></li>
<li><a>Users</a></li>
</ul>
</aside>
Add some styles
app/assets/stylesheets/admin/base/_variables.scss
$body-size: 16px !default;
// Responsiveness
// 960, 1152, and 1344 have been chosen because they are divisible by both 12 and 16
$tablet: 769px !default;
// 960px container + 40px;
$desktop: 1000px !default;
// 1152px container + 40;
$widescreen: 1192px !default;
// 1344px container + 40;
$fullhd: 1384px !default;
$white: #fff !default;
$orange: hsl(17, 83%, 57%);
$primary: $orange !default;
$primary-invert: $white !default;
// Link colors
$link: $primary !default;
$link-invert: $white !default;
$navbar-height: 3.25rem;
app/assets/stylesheets/admin/base/_base.scss
body {
overflow-x: hidden;
}
.columns {
&.is-fullheight {
min-height: calc(100vh - ( #{$navbar-height} - .75rem ) );
max-height: calc(100vh - ( #{$navbar-height} - .75rem ) );
height: calc(100vh - ( #{$navbar-height} - .75rem ) );
display: flex;
flex-direction: row;
justify-content: stretch;
.column {
overflow-y: auto;
}
}
}
.is-main-content {
background: $grey-lighter;
padding: 1rem 2.5rem 1rem 2rem;
}
app/assets/stylesheets/admin/components/_sidebar.scss
.is-sidebar-menu {
padding: 2.5rem;
background: $grey-dark;
li {
a {
color: $white;
}
}
}
app/assets/stylesheets/admin/components/_header.scss
.navbar {
.navbar-item {
.avatar {
margin-right: .65rem;
.is-rounded {
max-height: 100%;
}
}
}
}
Alright, if we restart our browser at this point and navigate to http://localhost:3000/admins/blogs
our dashboard should look like this.
If you got any error through this setup, feel free to drop me a line dev.renzo.diaz@gmail.com I’ll try to answer all your doubts asap.
In part 1 of this article, I mentioned this part 2 will cover CRUDS and Authentication, and React as well.
We'll, we will cover those points in part3, I don't want to make this article too long and don't mix with Rails back-end stuff.
Top comments (0)