管理画面へのログイン機能、管理画面トップページの作成
AdminLTE version3系をインストール
yarn add admin-lte@^3.1.0
これでnode_modulesとpackage.jsonとyarn.lockというファイルがインストールされ、node_modules/admin-lteディレクトリにデフォルトテンプレートが記載されているので今回はその中のstarter.htmlを使っていく。
管理者ページ用のマニフェストファイルの作成
今までは、app/assets/javascripts/application.js app/assets/stylesheets/application.scssに全て記述していたが、 管理者画面は一般ユーザー用と見た目が大きく異るため、別々で管理していく。
app/assets/javascripts/admin.js
//= require jquery3 //= require rails-ujs //= require admin-lte/plugins/bootstrap/js/bootstrap.bundle.min //= require admin-lte/dist/js/adminlte
app/assets/stylesheets/admin.scss
@import 'admin-lte/plugins/fontawesome-free/css/all.min.css'; @import 'admin-lte/dist/css/adminlte.css';
app/assets/javascripts/application.js
//= require_tree . #削除する
//= require tree.でapplication.js配下の全ファイルを読み込んでいました。 しかし、今回は同じ階層に管理者用のマニフェストファイルをファイルを配置するため、このままだと不必要な管理者用ファイルを読み込んでしまう。
config/initializars/assets.rb
Rails.application.config.assets.precompile += %w[admin.js admin.css]
管理者用コントローラー設定
管理系コントローラーに共通する機能を持つ基底クラス、Admin::BaseControllerを作成する。
他の管理系コントローラーは、Admin::BaseControllerを継承する。
application_controllerを継承するadmin/base_controllerを作成し、全ての管理画面用コントローラーはこのbase_controllerを継承する設計とするには、
rails g controller Admin::Base
app/controllers/admin/base_controller.rb
class Admin::BaseController < ApplicationController before_action :check_admin layout 'admin/layouts/application' private def not_authenticated flash[:warning] = t('defaults.message.require_login') redirect_to admin_login_path end def check_admin redirect_to root_path, warning: t('defaults.message.not_authorized') unless current_user.admin? end end
rails g controller Admin::Dashboards index
app/controllers/admin/dashboards_controller.rb
class Admin::DashboardsController < Admin::BaseController def index; end end
rails g controller Admin::User_sessions new
app/controllers/admin/user_sessions_controller.rb
class Admin::UserSessionsController < Admin::BaseController # BaseControllerを継承 skip_before_action :require_login, only: %i[new create] skip_before_action :check_admin, only: %i[new create] layout 'layouts/admin_login' def new; end def create # Soceryメソッド、emailとpasswordでログイン認証する。 @user = login(params[:email], params[:password]) if @user redirect_to admin_root_path, success: t('.success') else flash.now[:danger] = t('.fail') render :new end end def destroy logout redirect_to admin_login_path, success: t('.success') end end
usersテーブルにroleカラムを追加し、enumを使用して管理者とユーザーを区別
rails g migration add_role_to_users role:integer
class AddRoleToUsers < ActiveRecord::Migration[5.2] def change add_column :users, :role, :integer, null: false, default: 0 end end
rails db:migrate
app/models/user.rbに追加
enum role: { general: 0, admin: 1 }
enumとはモデルの数値カラムに対して文字列の名前を定義することができる。 今回は一般管理者をgeneral、管理者権限をadminとして定義していく。
ルーティング設定
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
/admin で始まるURLにしたいので、namespace :adminで名前空間を設定しする。
ビューの設定
app/helpers/application_helper.rb
def page_title(page_title = '', admin = false) base_title = if admin 'RUNTEQ BOARD APP(管理画面)' else 'RUNTEQ BOARD APP' end page_title.empty? ? base_title : page_title + ' | ' + base_title end
管理者用のページは「ダッシュボード | RUNTEQ BOARD APP(管理画面)」のように(管理画面)と出力したい。
app/views/admin/dashboards/index.html.erb
<% content_for(:title, t('.title')) %> <div class="container"> <div class="row"> ダッシュボードです </div> </div>
app/views/admin/layouts/application.html.erb
<!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 'admin', media: 'all' %> <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet"> </head> <body class="hold-transition sidebar-mini layout-fixed"> <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> <%= javascript_include_tag 'admin' %> </body> </html>
app/views/admin/shared/_footer.html.erb
<footer class="main-footer"> <strong>Copyright © 2019 RUNTEQ.</strong> All rights reserved. </footer>
app/views/admin/shared/_header.html.erb
<!-- 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"> <li class="nav-item"> <%= link_to t('defaults.logout'), admin_logout_path, class: 'nav-link', method: :delete %> </li> </ul> </nav> <!-- /.navbar -->
app/views/admin/shared/_sidebar.html.erb
<!-- 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> <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>
app/views/admin/user_sessions/new.html.erb
<% 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, local: true do |f| %> <%= f.label :email, User.human_attribute_name(:email) %> <div class="input-group mb-3"> <%= f.text_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>
app/views/layouts/admin_login.html.erb
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="robots" content="noindex, nofollow"> <title><%= page_title(yield(:title), admin: true) %></title> <meta name="viewport" content="width=device-width, initial-scale=1"> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'admin', media: 'all' %> </head> <body class="hold-transition login-page"> <div> <%= render 'shared/flash_message' %> <%= yield %> </div> </body> </html>
consoleで権限の変更
rails c [1] pry(main)> User.first.update_attributes(role: :admin) [2] pry(main)> User.first.role 実行結果=> "admin" [3] pry(main)> User.first.admin? 実行結果=> true
参考文献