[Rails][AdminLTE]管理画面18/20
はじめに
管理画面へのログイン機能を実装していきます。
要件
- 管理画面へのログイン画面のURLは
/admin/login
であること - 管理画面へのログインが成功した際のURLは
/admin
であること - Usersテーブルに role カラムが追加されていること(general: 一般, admin: 管理者)
- 管理画面へのログイン画面のページタイトルは ログイン | Article APP(管理画面) であること
- 管理画面のトップページは ダッシュボード | Article APP APP(管理画面) であること
- 管理画面へのログインに失敗した場合は
admin_login_path
にリダイレクトされること
管理者権限を持たないユーザーでログインした場合はroot_path
にリダイレクトされること - ログアウト後は管理画面のログインページにリダイレクトされること
- フラッシュメッセージが表示されること
- ログアウト時のメッセージは『ログアウトしました』と表示されること
- 成功時・・・『ログインしました』
- 失敗時・・・『ログインに失敗しました』
環境
Rails 6.1.7.3
ruby 3.0.0
tl;dr
-
AdminLTE
をインストールする - CSSとJSを読み込む
- プリコンパイルの設定
-
users
テーブルにrole
カラムを追加 -
enum
を設定する -
Admin
コントローラーを作成する -
routes.rb
を編集する - 管理画面のビューを作成する
- 管理画面をローカライズする
管理画面
管理画面は、ウェブアプリケーションやシステムの管理者が、システムの設定や管理、データの操作などを行うための画面です。一般的に、管理者や特権ユーザーがアプリケーションのバックエンドにアクセスし、データベースや設定を変更したり、他のユーザーのアカウントを管理したりするためのインターフェースです。
管理画面は、一般のユーザーには公開されないことが多く、セキュリティ上の理由からログインが必要な場合があります。管理者は、特別な権限を持つユーザーアカウントでログインし、管理画面にアクセスすることで、システム全体の設定や操作を行うことができます。
例えば、以下のような機能が含まれることがあります:
- ユーザーアカウントの管理:ユーザーの作成、編集、削除などの操作を行います。
- データの管理:データの閲覧、検索、編集、削除などを行います。
- システム設定の管理:アプリケーションの設定やパラメータの変更を行います。
- レポートの生成:集計データや統計情報の表示やダウンロードを行います。
- セキュリティ管理:アクセス権限の管理やログの監視、セキュリティ設定の管理を行います。
管理画面は、システム管理者や特定のユーザーにとって重要な役割を果たすものであり、システムの安全性や運用性を確保するために必要な機能を提供します。
今回はAdminLTE
を使っていきます。
AdminLTE
をインストールする
yarn add admin-lte@^3.2
CSSとJSを読み込む
node_modules
にあるadminlte.scss
とadminLTE.js
を読み込みます。
import 'admin-lte/build/js/AdminLTE'
@import 'admin-lte/build/scss/adminlte'
rails webpacker:compile
プリコンパイルの設定
アセットのプリコンパイルは、アプリケーションのデプロイ時に行われ、パフォーマンスを向上させるために最適化されたアセットファイルが生成されます。
アプリケーションに独自のJavaScriptやCSSを追加し、それをアセットパイプラインで結合・圧縮する必要がある場合に使用します。
一般的には、カスタムのJavaScriptやCSSファイル、サードパーティのライブラリやテンプレートのアセットファイルをプリコンパイルする必要がある場合に、この設定を使用します。
Rails.application.config.assets.precompile += %w( adminLTE.js adminlte.scss )
users
テーブルにrole
カラムを追加
enum
を使ってロールを管理するのでデータタイプをinteger
にします。
bin/rails generate migration AddRoleToUsers
invoke active_record
create db/migrate/20230708084922_add_role_to_users.rb
class AddRoleToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :role, :integer, default: 0, null: false
end
end
bin/rails db:migrate
Running via Spring preloader in process 27263
== 20230708084922 AddRoleToUsers: migrating ===================================
-- add_column(:users, :role, :interger, {:default=>0, :null=>false})
-> 0.0046s
== 20230708084922 AddRoleToUsers: migrated (0.0047s) ==========================
enum
を設定する
class User < ApplicationRecord
enum role: { general: 0, admin: 1 }
end
Admin
コントローラーを作成する
bin/rails g controller Admin::Base
create app/controllers/admin/base_controller.rb
invoke erb
create app/views/admin/base
このコントローラーファイルは、Admin
ネームスペース内の他のコントローラーが継承するベースとなるコントローラーです。Admin
ネームスペースのコントローラーで共通のロジックやフィルターを追加する場合に使用することができます。
Admin
ネームスペース
Admin
ネームスペースは、Railsアプリケーション内で管理者向けの機能や管理画面に関連するコードをグループ化するための仕組みです。
通常、Railsアプリケーションはユーザー向けのフロントエンドや一般的な機能を提供するために使用されますが、管理者が利用する機能は一般ユーザーとは異なるケースがあります。管理者向けの機能は、通常は認証や権限管理、データの管理や編集などを含みます。
Admin
ネームスペースを使用することで、管理者向けのコードを独自の名前空間でグループ化し、管理画面に関連するコントローラーやビュー、ヘルパー、モデルなどを整理することができます。これにより、コードの可読性や保守性を向上させることができます。
例えば、Admin::UsersController
や Admin::ProductsController
のように、管理者がユーザーや製品を管理するためのコントローラーを Admin
ネームスペース内に作成することができます。
また、ルーティングにも namespace
メソッドを使用して Admin
ネームスペースを適用することができます。これにより、管理画面用のルーティングをグループ化し、URLのパスやヘルパーメソッドにも admin
の接頭辞が付与されます。
namespace :admin do
resources :users
resources :products
end
以上のように、Admin
ネームスペースを使用することで、管理者向けの機能を組織化し、アプリケーション内の他の部分と分離して扱うことができます。
Admin用のトップページへ遷移するコントローラーを作成する
node_modules/admin-lte/starter.html
を参考して作成していきます。
bin/rails g controller Admin::Dashboards index
create app/controllers/admin/dashboards_controller.rb
route namespace :admin do
get 'dashboards/index'
end
invoke erb
create app/views/admin/dashboards
create app/views/admin/dashboards/index.html.erb
Admin用のログインコントローラーを作成する
node_modules/admin-lte/pages/example/login.html
を参考して作成していきます。
bin/rails g controller Admin::Sessions new
create app/controllers/admin/sessions_controller.rb
route namespace :admin do
get 'sessions/new'
end
invoke erb
create app/views/admin/sessions
create app/views/admin/sessions/new.html.erb
routes.rb
を編集する
admin認証用ルートを追加します。
namespace :admin do
root to: 'dashboards#index'
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
delete 'logout', to: 'sessions#destroy'
end
Admin用のレイアウトファイルを作成する
views/admin/layouts/
とviews/admin/shared/
を作成します。
node_modules/admin-lte/starter.html
を参考します。
<!DOCTYPE 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 %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<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>
</body>
</html>
<!-- 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 -->
<!-- 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.profile.thumb.url, class: 'img-circle elevation-2' %>
</div>
<div class="info">
<a href="#" class="d-block"><%= Current.user.user_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>
<!-- Main Footer -->
<footer class="main-footer">
<!-- To the right -->
<div class="float-right d-none d-sm-inline">
Anything you want
</div>
<!-- Default to the left -->
<strong>Copyright © 2014-2021 <a href="https://adminlte.io">AdminLTE.io</a>.</strong> All rights reserved.
</footer>
レイアウト宣言
Railsには、個別のコントローラやアクションに割り当てる特定のレイアウトをより正確に指定するため宣言する必要があります。
class Admin::BaseController < ApplicationController
layout 'admin/layouts/application'
end
Admin::Dashboards
コントローラーはAdmin::Base
コントローラーを継承する
継承すればレイアウトの宣言は不要です。
class Admin::DashboardsController < Admin::BaseController
skip_before_action :check_admin
before_action :login_required, unless: -> { Current.user }
def index
end
end
管理画面用のタイトルを設定する
module ApplicationHelper
def page_title(title)
base_title = 'Article APP'
title.empty? ? base_title : title + " | " + base_title
end
end
こちらのメソッドをadmin
を判断する用のif
文を追加します。
一般ユーザー向けのファイルに影響が出ないようにデフォルトをfalse
にします。
module ApplicationHelper
def page_title(title, admin = false)
base_title = if admin
'Article APP(管理画面)'
else
'Article APP'
end
title.empty? ? base_title : title + " | " + base_title
end
end
レイアウトファイルにtrue
を指定しましたね。
<title><%= page_title(yield(:title), admin: true) %></title>
Admin::Base
コントローラーを設定する
管理画面全体に共通する機能を追加します。
Admin
が未ログインの状態だとログインを促します。
ユーザーのロールがAdmin
ではないとページをroot_path
へ遷移します。
admin?
メソッドはenum
を設定した際にrole
カラムの1をadmin
としたので使えるようになっているメソッドです。
class Admin::BaseController < ApplicationController
before_action :check_admin
layout 'admin/layouts/application'
private
def login_required
flash.now[:danger]=t('defaults.message.require_login')
redirect_to admin_login_path unless Current.user
end
def check_admin
flash.now[:danger]=t('defaults.message.not_authorized')
redirect_to root_path unless Current.user&.admin?
end
end
Admin::Sessions
コントローラー
ログインに関しての記述を追加していきます。
Admin::Base
と違うレイアウトを使用するので宣言する必要があります。
ログインした後は、admin_root_path
へリダイレクトされ、admin/dashboards#index
アクションが呼び出されます。
このとき、管理者ではない一般ユーザでログインした場合は、before_action :check_admin
フィルタによって、一般ユーザ用のトップページへリダイレクトされます。
class Admin::SessionsController < Admin::BaseController
skip_before_action :check_admin, only: %i[new create]
layout 'admin/layouts/admin_login'
def new
end
def create
@user = User.find_by(email: params[:email])
if @user.present? && @user.authenticate(params[:password])
session[:user_id] = @user.id
flash[:success] = t('.success')
redirect_to admin_root_path
elsif @user.admin?
flash[:danger] = t('.danger')
render :new
else
flash[:danger] = t('defaults.message.not_authorized')
redirect_to root_path
end
end
def destroy
session[:user_id] = nil
flash[:success] = t('.success')
redirect_to admin_login_path
end
end
ログインのビューを作成する
adminログインフォームのテンプレートはnode_modules/admin-lte/pages/example/login.html
を参考にします。
<!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 %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body class="hold-transition login-page">
<div>
<%= render 'shared/flash_message' %>
<%= yield %>
</div>
</body>
</html>
ログインフォームを作成する
<%= 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>
管理画面をローカライズする
ja:
admin:
sessions:
new:
title: 'ログイン'
create:
success: 'ログインしました。'
danger: 'ログインに失敗しました。もう一度試してください。'
destroy:
success: 'ログアウトしました。'
dashboards:
index:
title: 'ダッシュボード'
終わりに
管理画面の実装でした。
復習して理解できるようになりましょう。
Discussion