How I Setup Ruby on Rails Following Digiteer’s Code Standards For Maximum Efficiency

Clark Wayne - Feb 14 - - Dev Community

Rails’ ‘magic’ shouldn’t be intimidating. Here’s a quick setup tutorial on how to get started on using Rails in accordance to Digiteer’s Code Guidelines.

Create new Rails app with PostgreSQL

rails new 'app-name' -d postgresql
Enter fullscreen mode Exit fullscreen mode

For Tailwindcss (Skip this if you will not use it)

bundle add tailwindcss-rails
Enter fullscreen mode Exit fullscreen mode
rails tailwindcss:install
Enter fullscreen mode Exit fullscreen mode

For slim-rails, a templating language

gem slim-rails # add this to Gemfile
Enter fullscreen mode Exit fullscreen mode
bundle install
Enter fullscreen mode Exit fullscreen mode

In config/application.rb file, add the following lines:

# config/application.rb
module AppName
  class Application < Rails::Application
    # Rest of the code...

    # Configure your timezone here
    config.time_zone = "Asia/Singapore" # Configure this to your local timezone
    config.active_record.default_timezone = :local # Add this

    # Set Slim as the default template engine
    config.generators do |g| # Add this
      g.template_engine :slim # Add this
    end # Add this
  end
end
Enter fullscreen mode Exit fullscreen mode

For Authentication using heartcombo/devise

bundle add devise
Enter fullscreen mode Exit fullscreen mode
rails generate devise:install
Enter fullscreen mode Exit fullscreen mode

You will be prompted to create your root path, “Ensure you have defined root_url to something in your config/routes.rb.
Create this file in app/views/layouts/_alerts.html.slim. This is a styled banner notifications in your application.

- flash.each do |type, message|
  div class="fixed top-4 right-4 z-50 max-w-sm p-4 rounded-lg shadow-lg border animate-fade-in-down #{type == 'notice' ? 'bg-green-100 border-green-200' : 'bg-red-100 border-red-200'}" id="flash-#{type}" data-flash-type="#{type}"
    div class="flex items-center"
      - if type == 'notice'
        svg.w-5.h-5.text-green-700 xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
          path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"
      - else
        svg.w-5.h-5.text-red-700 xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
          path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"
      div class="ml-3 text-sm font-normal #{type == 'notice' ? 'text-green-700' : 'text-red-700'}"
        = message
      button type="button" class="ml-1 text-sm text-gray-500 hover:text-gray-700 focus:outline-none" aria-label="Close" data-dismiss="#flash-#{type}"
        svg.w-5.h-5 xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
          path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"

  / JavaScript for auto-dismiss and close button
  javascript:
    document.addEventListener('click', function(event) {
      setTimeout(function() {
        const flash = document.querySelector('[data-flash-type="notice"], [data-flash-type="alert"]');
        if (flash) {
          flash.remove();
        }
      }, 5000);

      const button = event.target.closest('[data-dismiss]');
      if (button) {
        const flashMessage = document.getElementById(button.getAttribute('data-dismiss').substring(1));
        if (flashMessage) {
          flashMessage.remove();
        }
      }
    });
Enter fullscreen mode Exit fullscreen mode

Then call this alert component in your app/views/layouts/application.html.slim file. Preferrably at the header part of your application.

body.flex.flex-col.justify-center.items-center.bg-gray-100.text-gray-900.space-y-1.pb-8
    header.w-full.m-0
      = render "components/alerts" # Add this part
    = yield
Enter fullscreen mode Exit fullscreen mode

A quick background information: Digiteer follows the separation of concerns principle rigorously.
Throughout projects, Digiteer structure their applications to mainly two parts; Admin and Site. They assign the administrators to the ‘users’ model and the site visitors to the ‘customers’ model .

User is to admin as Customer is to site.
To get started, you have to think of your application having two roles. One is to serve the site visitors ‘customers’ through the site controllers and views and the other is to serve the administrators ‘users’ through the admin controllers and views.
Following the devise authentication setup, you will have to create these two devise models.

rails g devise user
Enter fullscreen mode Exit fullscreen mode
rails g devise customer
Enter fullscreen mode Exit fullscreen mode
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

Then create devise controllers for these two. Now remember, the user is to the admin and the customer is to the site. This is because the common users of the web applications that Digiteer builds for are the administrators or the client companies. And the customers of the clients are only capable to navigate in the Site route, hence, user is to admin as customer is to site.

Now, create the following controllers:

rails g devise:controllers admin # For the user
Enter fullscreen mode Exit fullscreen mode
rails g devise:controllers site # For the customers
Enter fullscreen mode Exit fullscreen mode

Then, paste this into your config/routes.rb file:

Rails.application.routes.draw do
  get "pages/home"
  # Routes for the admin users
  devise_for :users,
    path: "admin",
    controllers: {
      sessions: "admin/sessions",
      registrations: "admin/registrations",
      passwords: "admin/passwords"
    },
    path_names: {
      sign_in: "/login",
      password: "/forgot",
      confirmation: "/confirm",
      unlock: "/unblock",
      registration: "/register",
      sign_up: "/new",
      sign_out: "/logout",
      password_expired: "/password-expired"
    }

  namespace :admin do
    resources :post
  end

  # Routes for the site customers
  devise_for :customers,
    path: "/",
    controllers: {
      sessions: "site/sessions",
      registrations: "site/registrations",
      passwords: "site/passwords"
    },
    path_names: {
      sign_in: "/login",
      password: "/forgot",
      confirmation: "/confirm",
      unlock: "/unblock",
      registration: "/register",
      sign_up: "/new",
      sign_out: "/logout",
      password_expired: "/password-expired"
    }

  scope module: :site, path: "/" do
    resources :posts, controller: "/site/posts", as: :posts
    root "posts#index", as: :root
  end

  get "up" => "rails/health#show", as: :rails_health_check
end
Enter fullscreen mode Exit fullscreen mode

Basically, we assign the models (user, customer) to the following routes (admin, site).

Notice that I assigned the root route to site. Also, the default resource route of site is the posts resource. If you’re not doing this, then you can switch back to this:

# Routes for the site customers
  devise_for :customers,
    path: "/",
    controllers: {
      sessions: "site/sessions",
      registrations: "site/registrations",
      passwords: "site/passwords"
    },
    path_names: {
      sign_in: "/login",
      password: "/forgot",
      confirmation: "/confirm",
      unlock: "/unblock",
      registration: "/register",
      sign_up: "/new",
      sign_out: "/logout",
      password_expired: "/password-expired"
    }

  scope module: :site, path: "/" do
    resources :posts, controller: "/site/posts", as: :posts
    root "posts#index", as: :root
  end

  # Defines the root path route ("/") in config/routes.rb
  root "pages#home"
Enter fullscreen mode Exit fullscreen mode

If you want to separate the site scoping into your config/routes.rbfor maintainability, you can do so by separating the site scopes for both of the routes into separate files. First, copy the contents of your config/routes.rb file. Then under config directory, add a routes directory. Inside it, create two files named, “admin.rb” and “site.rb”. Then, paste the site scopes accordingly.

# config/routes/admin.rb
devise_for :users,
  path: "admin",
  controllers: {
    sessions: "admin/sessions",
    registrations: "admin/registrations",
    passwords: "admin/passwords"
  },
  path_names: {
    sign_in: "/login",
    password: "/forgot",
    confirmation: "/confirm",
    unlock: "/unblock",
    registration: "/register",
    sign_up: "/new",
    sign_out: "/logout",
    password_expired: "/password-expired"
  }

namespace :admin do
  resources :post
end
Enter fullscreen mode Exit fullscreen mode
# config/routes/site.rb
devise_for :customers,
  path: "/",
  controllers: {
    sessions: "site/sessions",
    registrations: "site/registrations",
    passwords: "site/passwords"
  },
  path_names: {
    sign_in: "/login",
    password: "/forgot",
    confirmation: "/confirm",
    unlock: "/unblock",
    registration: "/register",
    sign_up: "/new",
    sign_out: "/logout",
    password_expired: "/password-expired"
  }

scope module: :site, path: "/" do
  resources :posts, controller: "/site/posts", as: :posts
  root "posts#index", as: :root
end
Enter fullscreen mode Exit fullscreen mode

Then call both of the group routes in your config/routes.rb like so:

Rails.application.routes.draw do
  resources :posts
  get "pages/home"
  # Routes for the admin users
  draw :admin

  # Routes for the site customers
  draw :site

  # Root route is removed since it is handled by the 'site' module

  get "up" => "rails/health#show", as: :rails_health_check
end
Enter fullscreen mode Exit fullscreen mode

For authentication styling customization, you can access the Devise files by copying the Devise views to your app by running:

rails g devise:views # If you want to proceed with separate styling, proceed to the next step below.
Enter fullscreen mode Exit fullscreen mode

This will generate a devise folder under your app/views directory. You can now customize your authentication workflow.
If you want full and separate control of the styling for each of the following routes, you can do so by passing the group route name:

rails g devise:views admin
Enter fullscreen mode Exit fullscreen mode
rails g devise:views site
Enter fullscreen mode Exit fullscreen mode

Also, if you want to modify the authentication workflow, you can do so by generating the devise controllers like this:

rails g devise:controllers admin
Enter fullscreen mode Exit fullscreen mode
rails g devise:controllers site
Enter fullscreen mode Exit fullscreen mode

This will create an admin and site directory under app/controllers and inside them are the devise-specific controllers. Now, as you progress with your application, things might get a little cluttered. If you want to make your folder structure clean and tidy, you can make the devise-specific controllers to be placed within another folder. In this case you can follow this tutorial here.

You can now direct to these controllers your existing scaffolds or if you don’t have one yet, you can generate them and point it to these routes accordingly.

Then, you can now also start your application.

bin/dev # If using Tailwindcss
rails s # If using standalone Rails
Enter fullscreen mode Exit fullscreen mode

You should consider pushing your new changes to GitHub.

That's all! I hope you learn a thing or two. If you have any opinions, feel free to talk to me at the comment section! Happy Valentine's Day everyone!

.