AdminLTEを使って管理者用機能を実装する(トップページ)
- 実装したいこと
- 実装の流れ
- AdminLTEをインストールする
- マニフェストファイルの設定
- そのため、個別にファイルを読み込む記述に変更しました。
- Controller
- Userモデルにadmin判定用のカラムを追加する
- ルーティングの設定
- Views
- タイトルの設定
- 参考
実装したいこと
- 管理者専用ページを作りたい
- とりあえず今回はトップページのみ。
- AdminLTEを使用し、このようなページに仕上げる。
実装の流れ
- AdminLTE version3をインストール
- マニフェストファイル設定
- 管理者用コントローラー設定
- Userモデルに管理者判定用カラム追加
- ルーティング設定
- ビューの設定
アセットパイプラインについて全く理解できておらず、AdminLTEを反映させるのに時間がかかってしまいました。
現場RailsP266が分かりやすい。
AdminLTEをインストールする
AdminLTEとは、管理画面用のテンプレートです。
公式はこちら
GitHub - ColorlibHQ/AdminLTE: AdminLTE - Free admin dashboard template based on Bootstrap 4
公式、私の見方が悪いのかもしれないけど、ダウンロード方法しか見つからなかった。
yarn add admin-lte@^3.0
これで、node_modules/admin-lte
が作成されます。
このディレクトリ内に各種テンプレートがあるので、コピペして管理者用画面を作成していきます。
今回は、同ディレクトリ内のstarter.html
を使用していきます。
ただし、インストールしただけでは、ブラウザでCSSやJSを読み込むことができません。
読み込むための設定をしていきます。
マニフェストファイルの設定
今までは、app/assets/javascripts/application.js
app/assets/stylesheets/application.scss
に全て記述していましたが、
管理者画面は一般ユーザー用と見た目が大きく異るため、別々で管理していきます。
//= require jquery3 //= require rails-ujs //= require activestorage //= require popper //= require bootstrap-sprockets //= require edit_comment //= require preview
以前は、//= require tree.
でapplication.js配下の全ファイルを読み込んでいました。
しかし、今回は同じ階層に管理者用のマニフェストファイルをファイルを配置するため、このままだと不必要な管理者用ファイルを読み込んでしまいます。
そのため、個別にファイルを読み込む記述に変更しました。
新しく、管理者用ページのマニフェストファイルを作成します。
//= require jquery3 //= require jquery_ujs #rails_ujsにしたら何故かエラーになってしまったのでこっち //= require admin-lte/plugins/bootstrap/js/bootstrap.bundle.min #拡張子は省略できる //= require admin-lte/dist/js/adminlte.min
@import "font-awesome-sprockets"; @import "font-awesome"; @import 'admin-lte/plugins/fontawesome-free/css/all.min.css'; @import 'admin-lte/dist/css/adminlte.min.css';
アセット関連の設定
Rails.application.config.assets.paths << Rails.root.join('node_modules') #元々記載あり # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. Rails.application.config.assets.precompile += %w[admin.js admin.css] #コメントアウトを外す
他のマニフェストや、個別のスタイルシート/JavaScriptファイルをインクルードしたい場合は、config/initializers/assets.rbのprecompileという配列を使用します。 (Railsガイド)
これで、admin.js
admin.css
をプリコンパイルします。
Controller
管理系の機能を持つコントローラーを作成していきます。
管理系コントローラーに共通する機能を持つ基底クラス、
Admin::BaseController
を作成する他の管理系コントローラーは、
Admin::BaseController
を継承する
Admin::BaseController作成
最初、admin/baseってどうやってディレクトリ階層を作るのか悩んで手動で作ろうとしていましたが、Admin::
とすれば階層を自動で作ってくれる。
今後、管理系のコントローラーを追加したいときも同様。
rails g controller Admin::Base
他にも、ダッシュボード(トップページ)とログイン用のコントローラーを作っておきます。
rails g controller Admin::Dashboards index rails g controller Admin::User_sessions new
中身については、ビューファイルを作るときに。
Userモデルにadmin判定用のカラムを追加する
rails g migration add_role_to_users
class AddRoleToUsers < ActiveRecord::Migration[5.2] def change add_column :users, :role, :integer, default: 0, null: false #デフォルトは0(一般ユーザー)にする。 end end
一般ユーザーと管理者を区別するために、role
というカラムを新たに作成し、 整数(integer)で管理していきます。
最初、boolean型でtrue false判定で区別しようかと思っていましたが、今後権限の種類が増えることを考慮し、このような構造にします。
一般人 | 管理者 |
---|---|
0 | 1 |
追記したらrails db:migrate
する。
enumを設定する
enum
とは、先程作成したカラムの整数に定数を定義できるというものです。
enum role: { general: 0, admin: 1 }
このように定義すれば、この定数を使用することができます。
例えば、現ユーザーがadmin(管理者)か判定したいとき、current_user.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
で名前空間を設定します。
Views
現状は、views/layouts/application.html.erb
やviews/shared/_header.html.erb
のような全てに共通するテンプレートファイルを使用しています。
特定のコントローラーだけテンプレートを切り替えたいとき、どうすればいいのか悩みました。
管理者機能用テンプレートをviews/admin/layout/
に用意して、基底クラスのbase_controller
でlayout宣言
をすれば良さそうです。
(最初、dashboars_controllerなどにも個別で宣言を記述していましたが、base_controllerを継承する設定にするので個別の記載は不要でした。)
コントローラやアクション毎に使用するレイアウトを切り替える - Ruby on Rails入門
admin/base_controller.rb
class Admin::BaseController < ApplicationController layout 'admin/layouts/application' #layout宣言 end
admin/dashboards_controller.rb
class Admin::DashboardsController < Admin::BaseController def index; end end
class Admin::DashboardsController < Admin::BaseController
ここの記述でbase_controller
を継承します。
そのため、レイアウト宣言は不要です。
管理者用テンプレートファイル
<!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 %> <%= csp_meta_tag %> <%= 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' %> #headerをレンダーする <%= render 'admin/shared/sidebar' %> #sidebarをレンダーする <!-- Content Wrapper. Contains page content --> #コンテンツ部分 <div class="content-wrapper"> <%= render 'shared/flash_message' %> #フラッシュメッセージを読み込む <%= yield %> #bodyを読み込む </div> <!-- /.content-wrapper --> <%= render 'admin/shared/footer' %> #footerをレンダーする </div> <%= javascript_include_tag 'admin' %> #ブラウザにアセットを読み込ませる </body> </html>
node_modules/admin-lte/starter.html
から必要部分を切り分けしています。
header/sidebar/footer
は切り分けて、views/admin/shared
に配置しました。詳細は省略します。
管理者用共通ビューのこのファイルで、先程設定したadmin.js
admin.scss
を読み込んでいます。
ダッシュボード用ビュー
<% content_for(:title, t('.title')) %> #タイトルは次節で解説 <div class="content-wrapper"> <div class="row"> <p>ダッシュボードです</p> </div> </div>
タイトルの設定
タイトルは以前、カスタムヘルパーを使い動的に出力していました。 study-diary.hatenadiary.jp
今回、管理者用のページは「ダッシュボード | 固定タイトル(管理用)」のように、(管理用)と出力したいです。
module ApplicationHelper def page_title(page_title = '', admin = false) base_title = if admin 'Ruby on Rails 学習記録(管理画面)' else 'Ruby on Rails 学習記録' end page_title.empty? ? base_title : page_title + ' | ' + base_title end
デフォルトでadmin = false
にしておきます。
これで、今まで作ってきたタイトルはadmin: false
なので書き換えが不要です。
最後に評価された式を戻り値としてbase_title
に代入しています。
ちなみに、私が最初に実装したコードはこっち。
反省用に記録しておきます。
条件分岐するのではなく、admin用のカスタムヘルパーを新たに作成してしまいました。
これだとビューに反映させるときに、汎用的に使えないので没です。
三項演算子も使っていないのでコードが冗長になっています。
module ApplicationHelper # ページごとの完全なタイトルを返す def page_title(page_title = '') base_title = 'Ruby on Rails 学習記録' if page_title.empty? base_title else page_title + ' | ' + base_title end end def adminpage_title(page_title = '') base_title = 'Ruby on Rails 学習記録(管理画面)' if page_title.empty? base_title else page_title + ' | ' + base_title end end end
管理用共通テンプレートに読み込み
繰り返しになるので、タイトル部分だけ抜粋
admin: true
にします。
<title><%= page_title(yield(:title), admin: true) %></title>
各ビュー
<% content_for(:title, t('.title')) %> #titleは翻訳ファイルに記入
各ビューでこのように読み込めばOK
翻訳ファイル
admin/dashboards_controller
のように階層があるコントローラーの翻訳ファイルはどういうふうに書けばいいのか迷いました。
このように翻訳ファイルでも階層を作ってあげれば大丈夫でした。
参考
[管理画面]Rails 5 に yarnでインストールした「AdminLTE3.0.0-alpha.2」 を適用させる方法 - Qiita
俺たちは雰囲気でAdminLTEを使っている - Qiita
コントローラやアクション毎に使用するレイアウトを切り替える - Ruby on Rails入門
https://pikawaka.com/rails/enum#boolean%E3%81%AE%E5%A0%B4%E5%90%88