Railsでログイン機能をつくってみました
今回作るログイン機能はタスク管理アプリで
初回利用時にユーザー登録を行い、その後利用するときは「私は先日に登録したユーザーです」と言う認証を行うやり方。
セッションとCookie
ログイン機能を実装する前に前提知識となるセッションとCookieについてはこちらの記事に書きました。 https://qiita.com/ombossk0720/items/5345b8ef267749e550feUserモデルを作る
認証機能を作るにはアプリに新しい概念を加える必要がある。 それはアプリケーションを利用する概念。 そこでユーザーを表すUserモデルを作る。 タスク管理アプリのUserモデルに最低限必要なのはメールアドレスとパスワード。 ただそれだけでは、ユーザーを表すのに常に長ったらしいメールアドレスか、暗号のような数字を 表示しなければいけなくなるので、扱いやすいようにユーザー名を別途保持することにする。generateコマンドを使ってUserモデルをつくってみる
generateコマンドによって、データベースにuserテーブルを作るためにマイグレーションファイルとUserモデルが作られた。
早速migrationしたいところだがまずマイグレーションファイルを編集。
名前やメールアドレスやパスワードには何かしらの文字列が必ず入るのでこれらの属性にNULLが入ることはない。
また、同じメールアドレスをもつユーザーが複数人いることはない。ありえない値が入ることを防ぐために生成した
マイグレーションファイルを開いて以下のように書き換える。
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :name, null: false
t.string :email, null: false
t.string :password_digest, null: false
t.timestamps
t.index :email, unique: true
end
end
end
書き換えたらマイグレーションを実行して、データベースにusersテーブルを作成する。
% bin/rails db:migrate
usersテーブルが作られ、generateコマンドでUserモデルも作られている。
ユーザー管理機能一式を追加する
次にアプリケーションの利用者をどうやってUserとしてデータベースに登録するか検討します。よくある形は1,未登録のユーザーが自らサインアップを行う。
2,管理者がユーザーを登録することで、ユーザーがアプリケーションを利用できるようにする。
1は全世界の個人に向けて提供する場合に、2は特定のグループに属する提供する場合に適している。
そしてユーザー管理機能は管理者だけ触れるようにする必要がある。
Userモデルにadminフラグを追加する
まず、ユーザーが管理者かどうかを表すフラグを追加する。 以下のコマンドでマイグレーションファイルの雛形を作成する。% bin/rails g migration add_admin_to_users
ファイルを開き以下のように編集。
class AddAdminToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :admin, :boolean, default: false, null: false
end
end
このマイグレーションはusersテーブルにadminと言うフラグのカラムを追加する。早速適用。
% bin/rails db:migrate
ユーザー管理のためのコントローラを実装する
次にユーザー管理のためのコントローラを作成。 ここでは「管理系」の機能として「ユーザー管理」を行うのでAdmin::UsersControllerと言う名前をつける。 この名前は、Adminと言うモジュールの名前空間の中にUsersControllerと言うクラスを定義するという意味になる。 Railsではモジュール階層を、コードを保存するためのディレクトリ階層に対応させている。app/controllers/admin/users_controller.rbと言うファイルが対応するようになる。 これから「管理系」の機能を足したいとき、Admin::のついたコントローラを追加していけばコードがAdminディレクトリの下にまとまって わかりやすくなる。まず、Admin::UsersControllerを画面を伴うGETアクションのビューとともに以下のコマンドで作ります。
% bin/rails g controller Admin::Users new edit show index
generateの機能によってnew,edit,show,indexのからのアクションとデフォルトのビューができた。
合わせてroutes.rbにも自動で定義が追加されるがこれは決めている仕様と合わないので、エディタで編集。
admin/users/で始まるURLの書かれた記述を全て削除して次のように内容を編集する。
Rails.application.routes.draw do
namespace :admin do
resorces :users
end
root to: 'tasks#index'
resources :tasks
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
これで想定したURLで適切なアクションにリクエストが飛ぶようになる。各機能のURLを得るには、admin_users_pathやadmin_user_pathなど
adminがついたヘルパーメソッドを使う。
ここからは各機能を作り込んでいく。
登録の機能
コントローラ(app/controllers/admin/users_controller.rb)とビュー(app/controllers/admin/users/new.html.slim)を以下のように変更。class Admin::UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def edit
@user = User.find(params[:id])
end
def create
@user = User.new(user_params)
if @user.save
redirect_to admin_user_url(@user), notice: "ユーザー「#{@user.name}」を登録しました。"
else
render :new
end
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to admin_user_url, notice: "ユーザー「#{@user.name}」を更新しました。"
else
render :edit
end
end
def destroy
@user = User.find(params[:id])
@user.destroy
redirect_to admin_users_url, notice: "ユーザー「#{@user.name}」を削除しました。"
end
private
def user_params
params.require(:user).permit(:name, :email, :admin, :password, :password_confirmation)
end
end
ここからnew,edit,show,indexと次のようにコードを書いてもいいのですが、面倒なのでパーシャルを使います。
h1 ユーザー登録
= form_with model: [:admin, @user], local: true do |f|
.form-group
= f.label :name, '名前'
= f.text_field :name, class: 'form-control'
.form-group
= f.label :email, 'メールアドレス'
= f.text_field :email, class: 'form-control'
.form-check
= f.label :admin, class: 'form-check-label' do
= f.check_box :admin, class: 'form-check-input'
| 管理者権限
.form-group
= f.label :password, 'パスワード'
= f.password_field :password, class: 'form-control'
= f.submit '登録する', class: 'btn btn-primary'
これを各それぞれのファイルに書き込むのはしんどそうですよね。
ここから先の手順でやれば書き込んだことと同じことになります。パーションファイルはファイル名を_から始めます。
今回はform系のことなのでviews/admin/users/index.html.slimと同じ階層に新規で_form.html.slimファイルを作成して
以下のようにコードを入力していきます。
- if user.errors.present?
ul#error_explanation
- user.errors.full_messages.each do |message|
li= message
= form_with model: [:admin, user], local: true do |f|
.form-group
= f.label :name, '名前'
= f.text_field :name, class: 'form-control'
.form-group
= f.label :email, 'メールアドレス'
= f.text_field :email, class: 'form-control'
.form-check
= f.label :admin, class: 'form-check-label' do
= f.check_box :admin, class: 'form-check-input'
| 管理者権限
.form-group
= f.label :password, 'パスワード'
= f.password_field :password, class: 'form-control'
.form-group
= f.label :password_confirmation, 'パスワード(確認)'
= f.password_field :password_confirmation, class: 'form-control'
= f.submit '登録する', class: 'btn btn-primary'
!インデントエラーがよく発生するので注意!
_form.html.slimが作成できたら
index,edit,show,newファイルを以下のように編集していきます。
h1 ユーザー一覧
= link_to '新規登録', new_admin_user_path, class: 'btn btn-primary'
.mb-3
table.table.table-hover
thed.thed-default
tr
th= User.human_attribute_name(:name)
th= User.human_attribute_name(:email)
th= User.human_attribute_name(:admin)
th= User.human_attribute_name(:created_at)
th= User.human_attribute_name(:updated_at)
th
tbody
- @users.each do |user|
tr
td= link_to user.name,[:admin, user]
td= user.email
td= user.admin? ? 'あり' : 'なし'
td= user.created_at
td= user.updated_at
td
= link_to '編集', edit_admin_user_path(user), class: 'btn btn-primary mr-3'
= link_to '削除', [:admin, user], method: :delete,data: { confirm: "ユーザー「#{user.name}」を削除します。よろしいですか?"}, class: 'btn btn-danger'
h1 ユーザー登録
.nav.justify-content-end
= link_to '一覧', admin_users_path, class: 'nav-link'
= render partial: 'form', locals: { user: @user }
h1 ユーザーの編集
.nav.justify-content-end
= link_to '一覧', admin_users_path, class: 'nav-link'
= render partial: 'form', locals: { user: @user }
h1 ユーザーの詳細
.nav.justify-content-end
= link_to '一覧', admin_users_path, class: 'nav-link'
table.table.table-hover
tbody
tr
th= User.human_attribute_name(:id)
td= @user.id
tr
th= User.human_attribute_name(:name)
td= @user.name
tr
th= User.human_attribute_name(:email)
td= @user.email
tr
th= User.human_attribute_name(:admin)
td= @user.admin? ? 'あり' : 'なし'
tr
th= User.human_attribute_name(:created_at)
td= @user.created_at
tr
th= User.human_attribute_name(:updated_at)
td= @user.updated_at
= link_to '編集', edit_admin_user_path, class: 'btn btn-primary mr-3'
= link_to '削除', [:admin, @user], method: :delete, data: { confirm: "ユーザー「#{@user.name}」を削除します。よろしいですか?" }, class: 'btn btn-danger'
configも追加します
models:
task: タスク
attributes:
task:
id: ID
name: 名称
description: 詳しい説明
created_at: 登録日時
updated_at: 更新日時
user:
name: 名前
email: メールアドレス
admin: 管理者権限
password: パスワード
password_confirmation: パスワード(確認)
created_at: 登録日時
updated_at: 更新日時
以上で、ユーザー管理機能の基礎となる部分は出来上がりで/admin/usersにアクセスすれば利用することができます。
長い道のりでした。
"参考書籍:現場で使える Ruby on Rails5速習実践ガイド"