15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Rails】AdminLTEを用いて管理画面機能を搭載

Posted at

##手順
1.AdminLTE3をインストール
2.管理者画面用のマニフェストファイルの設定
3.管理者権限を判定する為のカラムを追加
4.管理者用のコントローラー作成
5.ルーティングの設定
6.ビューファイルの作成

##1.AdminLTE3をインストール
AdminLTE3とは、Bootstrap3をベースにした、管理画面等のテンプレートテーマ。
今回はyarnを使ってAdminLTE3をインストールする。

ターミナルにて**yarn add admin-lte@^3.1**を実施。
するとnode_modules/package.json/yarn.lockというファイルが生成される。

多数テンプレートファイルが用意されているので、その中のnode_modules/admin-lte/starter.htmlを参照。

読み込むべきCSSファイル・JSファイルが記載されているので、これを参照しながらadmin.scssadmin.js2つのマニュフェストファイルを作成。

マニフェストファイルというのは、どのCSSファイルやJavascriptファイルを呼び出すかを記載したファイルのこと。

##2.管理者画面用のマニフェストファイルの設定
今まで一般ユーザー用のマニフェストファイルは

app/assets/javascripts/application.js
app/assets/stylesheets/application.scssだったが、

管理者画面は一般ユーザーの画面と構成や見た目が大きく異なる事から、別々に管理するのが一般的なのでその設定をしていく。

まずはjsファイルから設定していく。

app/assets/javascripts/application.js
#この1文を削除
//= require_tree . 
app/assets/javascripts/admin.js
#admin.jsを作成し以下を追記
//= require jquery3
//= require jquery_ujs

//= require admin-lte/plugins/bootstrap/js/bootstrap.bundle.min
//= require admin-lte/dist/js/adminlte.min

# これは必要ない  //= require admin-lte/plugins/jquery/jquery.min
#これはjQuery本体を読み込む記述なのでGemfileに記述してインストールしているgemのjquery-railsと重複しているので不要

require_treeには以下の特徴がある。

■指定したディレクトリ以下のすべてのJSファイルを読み込む
require_tree .の場合は同じ階層以下すべてのJSファイルを読み込むということ。

■読み込む順序は指定できない。
そのため、利用しているJSファイルが特定の読み込み順に依存している場合に不都合がある。

今回はapplication.jsと同じ階層にadmin.jsを作成したので、application.jsrequire_tree .してしまうと、application.jsadmin.jsを読み込んでしまう。

つまり管理画面でしか使わないはずのファイルまで、application.jsで読み込んでしままう。それを避けるためにrequire_tree .は使わずに、ファイルを、個別に必要な順序で読み込む必要がある。

次にscssファイルを設定。

admin.scss
#以下の2文を追加
@import 'admin-lte/plugins/fontawesome-free/css/all.min.css';
@import 'admin-lte/dist/css/adminlte.css';

application以外のマニフェストファイルを個別に読み込む場合は、プリコンパイルの設定をしないと、そのファイルは対象外とされてしまうためエラーが起きてしまうので、その設定も行う。

プリコンパイルとは、「事前に(pre)」コンパイルを行うこと。
コンパイルとは、SCSS等ブラウザが直接は読めない形式のファイルを、JSやCSSに変換してあげるということ。
何に対して「事前」かというと、**「rails serverが走るよりも前」**に該当する。

config/initializers/aseets.rb
#この1行がコメントアウトされいるので、表示させる
Rails.application.config.assets.precompile += %w( admin.js admin.css )

##3.管理者権限を判定する為のカラムを追加
管理者権限を判定するカラムを今回は、一般ユーザと管理者を区別し、整数のinteger型roleカラムを追加する。

ターミナルでrails g migration add_to_role_usersを実行。

add_to_role_users.rb
class AddRoleToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :role, :integer, default: 0, null: false
     #↑一般ユーザが0・管理者は1とし、デフォルトは一般ユーザである0と指定
  end
end

usersモデルenumの設定をしていく。一般ユーザーをgeneral、管理者をadminとして定義。

model/user.rb
#この1文を追記
enum role: { general: 0, admin: 1 }

enumについての詳細はここ

##4.管理者用のコントローラー作成
管理者用のコントローラ-を作成するにあたって、「管理系」のカテゴリとして区分したいため、Admin::BaseControllerという名前で作成。
この名前は、Adminというモジュールの名前空間の中にBaseControllerというクラスを定義するという意味になる。

Railsではモジュール階層を、コードを保存するためのディレクトリ階層に対応させているので、admin/base_controller.rbというファイルが対応する事になる。

後々、管理系の機能を増やす時に、Admin::のついたコントローラーを追加していけば、コードがadminディレクトリ配下にまとまるので視認性が良くなる。

ターミナル.
rails g controller Admin::Base

#↓管理者用のトップページ用のコントローラーを作成
rails g controller Admin::Dashboards index

#↓管理者用のログイン用のコントローラーを作成
rails g controller Admin::User_sessions

図で表すとこんな感じ。
Image from Gyazo

ではコントローラーの中身を記述していく。
管理者機能の根幹となるAdmin::BaseController

controllers/admin/base_controller.rb
class Admin::BaseController < ApplicationController
  bofore_action :check_admin
   #↓layout宣言
  layout 'admin/layouts/application'

  private

  def not_authenticated
    redirect_to admin_login_path, warning: "ログインしてください"
  end

    #↓管理者権限を持っているか確認する
  def check_admin
    redirect_to root_path, warning: "管理者権限を持っていません" unless current_user.admin?
  end
end

通常、何も指定が無ければコントローラーはapp/views/layouts/application.html.erbをレイアウトとして探索する。

管理者機能の根幹クラスであるAdmin::BaseControllerで個別の管理者用画面のレイアウトファイルを呼び込むようにlayout宣言がいる。

controllers/admin/user_sessions_controller.rb
class Admin::UserSessionsController < Admin::BaseController
  skip_before_action :require_login, only: %i[new create]
  skip_before_action :check_admin, only: %i[new create]
   # ↓ログインページ用のレイアウトを用意するので宣言
  layout 'admin/layouts/admin_login'

  def new; end

  def create
   @user = login(params[:email], params[:password])
   if @user
      redirect_to admin_root_path  , success: 'ログインしました'
    else
      flash.now[:danger] = 'ログインに失敗しました'
      render :new
    end
  end

  def destroy
    logout
    redirect_to admin_login_path, success: 'ログアウトしました'
  end
end

Admin::UserSessionsコントローラーAdmin::Baseコントローラーを継承してるで、そのままではadmin/layouts/applicationをレイアウトとして使用する。

しかしログイン画面は違う見た目にするので、別のログインページ用のレイアウトファイルを用意してlayout宣言をする必要がある。

また、ログインしていないユーザや、管理者権限のないユーザでも、ログイン画面が表示されるようにskip_before_actionでフィルタをスキップさせる。

ログインした後はadmin_root_pathへリダイレクトされ、admin/dashboards#indexが呼び出される。

このとき、管理者ではない一般ユーザでログインした場合は、before_action :check_adminフィルタによって、一般ユーザ用のトップページへリダイレクトされる。

##5.ルーティングの設定
Adminモジュールの名前空間を使用したコントローラを作成したので、それに対応するようにルーティングにも名前空間を設定。

routes.rb
namespace :admin do
  root to: 'dashboards#index'
  get 'login', to: 'user_sessions#new'
  post 'login', to: 'user_sessions#create'
  delete 'logout', to: 'user_sessions#destroy'
end

##6.ビューファイルの作成
starter.htmlから流用してレイアウトファイルを作成。
管理者画面用のマニフェストファイルadmin.scssadmin.jsを読み込む記述を忘れずに注意。

views/admin/layouts/application.html.rb
<!DOCTYPE html>

<html>
  <html>
  <head>
    <meta charset="utf-8">
    <meta lang='ja'>
    <meta name="robots" content="noindex, nofollow">
    <title><%= page_title(yield(:title), admin: true) %></title>
    <%= csrf_meta_tags %>
          # ↓ここでadmin.scssを読み込む
    <%= stylesheet_link_tag 'admin', media: 'all' %>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
  </head>

  <body class="hold-transition sidebar-mini">
  <div class="wrapper">

    <%= render 'admin/shared/header' %>
    <%= render 'admin/shared/sidebar' %>
 
    <!-- Content Wrapper. Contains page content -->
    <div class="content-wrapper">
     <%= render 'shared/flash_message' %>
     <%= yield %> 
    </div>
    <!-- /.content-wrapper -->

    <%= render 'admin/shared/footer' %>

  </div>
      # ↓ここでadmin.jsを読み込む
  <%= javascript_include_tag 'admin' %>
  </body>
</html>

・ヘッダー

admin/shared/_header.html.rb
<!-- Navbar -->
  <nav class="main-header navbar navbar-expand navbar-white navbar-light">
    <!-- Left navbar links -->
    <ul class="navbar-nav">
      <li class="nav-item">
        <a class="nav-link" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a>
      </li>
    </ul>

    <!-- Right navbar links -->
    <ul class="navbar-nav ml-auto">
      <!-- Navbar Search -->
      <li class="nav-item">
        <%= link_to t('defaults.logout'), admin_logout_path, method: :delete, class: 'nav-link' %>
      </li>
    </ul>
  </nav>
<!-- /.navbar -->

・フッター

admin/shared/_footer.html.rb
<!-- Main Footer -->
<footer class="main-footer">
  <strong>Copyright © 2022 SUMPLE.</strong>
  All rights reserved. 
</footer>

・サイドバー

admin/shared/_sidebar.html.rb
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary elevation-4">
  <!-- Brand Logo -->
  <a href="index3.html" class="brand-link">
    <%= image_tag 'AdminLTELogo.png', class: 'brand-image img-circle elevation-3' %>
    <span class="brand-text font-weight-light">AdminLTE 3</span>
  </a>

  <!-- Sidebar -->
  <div class="sidebar">
    <!-- Sidebar user panel (optional) -->
    <div class="user-panel mt-3 pb-3 mb-3 d-flex">
      <div class="image">
        <%= image_tag current_user.avatar_url, class: 'img-circle elevation-2' %>
      </div>
      <div class="info">
        <a href="#" class="d-block"><%= current_user.decorate.full_name %></a>
      </div>
    </div>
    <!-- Sidebar Menu -->
    <nav class="mt-2">
      <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
        <li class="nav-item">
          <%= link_to '#', class: "nav-link" do %>
            <i class="nav-icon far fa-file"></i>
            <p>
              掲示板一覧
            </p>
          <% end %>

        <li class="nav-item">
          <%= link_to '#', class: "nav-link" do %>
            <i class="nav-icon far fa-user"></i>
            <p>
              ユーザ一一覧
            </p>
          <% end %>
        </li>
      </ul>
    </nav>
    <!-- /.sidebar-menu -->
  </div>
  <!-- /.sidebar -->
</aside>

・管理者ログイン画面
adminログインフォームのテンプレートはnode_modules/admin-lte/pages/example/login.htmlを参考に作成。

views/admin/layouts/admin_login.html.rb
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title><%= page_title(yield(:title), admin: true) %></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
     # ↓admin.scssを読み込む
    <%= stylesheet_link_tag 'admin', media: 'all' %>
  </head>
  <body class="hold-transition login-page">
    <div>
      <%= render 'shared/flash_message' %>
      <%= yield %>
    </div>
  </body>
</html>
views/admin/user_sessions/new.html.rb
<%= content_for(:title, t('.title')) %>
<div class="login-box">
  <div class="login-logo">
    <h1><%= t('.title') %></h1>
  </div>
  <!-- /.login-logo -->
  <div class="card">
    <div class="card-body login-card-body">

      <%= form_with url: admin_login_path, locale: true do |f| %>
        <%= f.label :email, User.human_attribute_name(:email) %>
        <div class="input-group mb-3">
          <%= f.email_field :email, class: 'form-control', placeholder: 'Email'%>
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-envelope"></span>
            </div>
          </div>
        </div>
        <%= f.label :password, User.human_attribute_name(:password) %>
        <div class="input-group mb-3">
          <%= f.password_field :password, class: 'form-control', placeholder: :password %>
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-lock"></span>
            </div>
          </div>
        </div>

        <div class="row">
          <div class="col-12">
            <%= f.submit t('defaults.login'), class: 'btn btn-block btn-primary' %>
          </div>
        </div>
      <% end %>
    </div>
  </div>
</div>

・管理者画面用トップページ

views/admin/dashboards/index.html.rb
<%= content_for(:title, t('.title')) %>
<div class="content-wrapper">
  <div class="row">
    <p>ダッシュボードです</p>
  </div>
</div>

管理画面用のページタイトルの設定
管理者画面が出ている時だけ、ページタイトルの末尾に(管理画面)と表記させる。

app/helpers/applicaton_helper.rb
module ApplicationHelper
  def page_title(page_title = '', admin = false)
    base_title = if admin
                  'SAMPLE BOARD APP(管理画面)'
                 else
                  'SAMPLE BOARD APP'
                 end

    page_title.empty? ? base_title : page_title + ' | ' + base_title
  end
end

この設定で、デフォルトをadmin = falseとすることによって、既存の一般ファイルに影響が出ないようにし、管理者用レイアウトファイルでadmin: trueを設定しておくことで、ページタイトルに(管理画面)がつく。
(このadmin: trueの部分のこと。
<title><%= page_title(yield(:title), admin: true) %></title>

##参考記事
[Rails] AdminLTEを使って管理画面機能を作成
Ruby on Rails プリコンパイル という言葉の定義は?

15
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?