Railsのシンプルなログイン機能 Part3

目次

はじめに

 ログイン機能の勉強として機能を細分化しつつ実装します。

 理解するための実装なので設計上好ましくない実装が含まれます。できるだけシンプルに実装し、理解し易さを求めたので今回のような実装になりました。ないとは思いますが、後述するコードを参考にする際はお気をつけください。

  • 環境
バージョン
OS OS X 10.15.6
ruby 2.6.4
rails 6.0.3

 前回の続きをやっていきます。前回はパスワードの暗号化や登録情報のバリデーションを実装しました。それに次の項目を加えます。

  1. ユーザー編集
  2. ユーザー削除

設計

  • データベース
カラム 用途 データ型
id 自動生成のID intger
name ユーザーネーム string
password_digest パスワード string
  • 機能(追加)

    1. ユーザー編集機能

    2. ユーザー削除機能

  • ビュー

ファイル名 内容
index.html.erb ユーザー一覧
new.html.erb 登録画面
edit.html.erb 編集画面

実装

ユーザー編集機能の追加

編集をする時の流れは以下の通りです。

① ユーザー一覧の編集したいユーザーの編集ボタンを押す。

ルーターによりeditアクションが実行され編集ページにリダイレクトされる。
(この時、編集したいユーザーの情報がインスタンス変数として渡される。)

③ ユーザー情報を編集し、更新ボタンを押す。

ルーターによりupdateアクションが実行され成功すればユーザー一覧にリダイレクトし、失敗したら編集ページにエラー表示をする

  • ルーティングの設定

次のようにルーティングを設定します。

Rails.application.routes.draw do
  get 'users/index'
  get 'users/new'
  get 'users/home'
  get '/users/create', to: 'users#new'
  post '/users/create'
  get '/user/:id/edit', to: 'users#edit', as: 'edit_users'
  patch '/users/:id', to: 'users#update'

  root 'users#index'
end

as: 'edit_users'も追加していることによりedit_users_pathヘルパーが使えるようになります。

  • viewの編集

ユーザー一覧に編集ボタンを追加します。

<h1>ユーザー一覧</h1>
<%= link_to '登録画面へ', '/users/new' %>
<table>
  <tr>
    <th>ユーザー名</th>
  </tr>

  <% @users.each do |user| %>
  <tr>
    <td><%= user.name %></td>
    <td><%= link_to 'Edit', edit_users_path(user) %></td>
  </tr>
  <% end %>
</table>

rails server を起動してユーザー一覧ページの編集ボタンを開発ツールで見るとリンク先が<a href="/user/5/edit">Edit</a>のようにレンダリングされているのがわかります。

  • editアクションの追加

コントローラーを次のように変更します。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

  def edit
    @user = User.find(params[:id])
  end

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

edit用のviewファイルも追加します。登録ページ(new.html.erb)を少し変えたものになります。

<h1>ユーザー編集</h1>
<%= link_to 'ユーザー一覧', '/users/index' %>
<form action="/users/<%= params[:id] %>" method="post">
<input type="hidden" name="_method" value="patch">
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <ul>
    <li>
      <label for="user_name">Name:</label>
      <input type="text" id="user_name" name="user[name]" value="<%= @user.name %>">
    </li>
    <li>
      <label for="user_password">Password:</label>
      <input type="password" id="user_password" name="user[password]">
    </li>
    <li>
      <label for="user_password">Password(confirm):</label> 
 
     <input type="password" id="user_password_confirmation" name="user[password_confirmation]">
    </li>
    <li>
      <input type="submit" value="編集">
    </li>
  </ul>
</form>

追加した1行は<input type="hidden" name="_method" value="patch">です。 また、名前入力欄には編集前の名前を表示するためにinputタグのvalue属性をvalue="<%= @user.name %>"にしています。フォームの送信先<form action="/users/<%= params[:id] %>" method="post">としています。次の項でupdateアクションを追加します。

  • updateアクションの追加

Userコントローラーにupdateアクションを追加します。updateアクションはDBにユーザー情報を上書きするだけなのでviewファイルを新たに作る必要はありません。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

  def edit
    @user = User.find(params[:id])
  end

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

  def create
    @user = User.find(params[:id])

    if @user.update
      redirect_to '/users/index'
    else
      render '/users/edit'
    end
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

createアクションと似ています。新しくUserオブジェクトを作るのではなくidでDBから検索し、paramsの値を引数にupdateメソッドでDBに保存します。この時Rails serverのログを見るとSQLのクエリが登録時と編集時で異なることがわかります。

登録時(INSERTでDBに保存している)

INSERT INTO "users" ("name", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?)  
[["name", "test"], ["password_digest", "$2a...KG"], ["created_at", "2020-09-29 06:16:15.541364"], ["updated_at", "2020-09-29 06:16:15.541364"]]

編集時(UPDATEでDBに保存している)

UPDATE "users" SET "name" = ?, "password_digest" = ?, "updated_at" = ? WHERE "users"."id" = ?  
[["name", "change3"], ["password_digest", "$2...li"], ["updated_at", "2020-09-29 06:16:29.407794"], ["id", 3]]

以上で編集機能が追加できました。

ユーザー削除機能の追加

削除をする時の流れは以下の通りです。

① ユーザー一覧の削除したいユーザーの削除ボタンを押す。

ルーターによりdestroyアクションが実行され、確認メッセージをブラウザに表示した後ユーザーが削除される。

③ 削除完了後、ユーザー一覧にリダイレクトされる。

  • ルーティングの設定

次のようにルーティングを設定します。

Rails.application.routes.draw do
  get 'users/index'
  get 'users/new'
  get 'users/home'
  get '/users/create', to: 'users#new'
  post '/users/create'
  get '/user/:id/edit', to: 'users#edit', as: 'edit_users'
  patch '/users/:id', to: 'users#update'
  delete '/users/:id', to: 'users#destroy', as 'destroy_users'

  root 'users#index'
end
  • viewの編集

ユーザー一覧に削除ボタンを追加します。

<h1>ユーザー一覧</h1>
<%= link_to '登録画面へ', '/users/new' %>
<table>
  <tr>
    <th>ユーザー名</th>
  </tr>

  <% @users.each do |user| %>
  <tr>
    <td><%= user.name %></td>
    <td><%= link_to 'Edit', edit_users_path(user) %></td>
    <td><%= link_to 'Destroy', destroy_users_path(user), method: :delete, data: { confirm: 'Are you sure' } %></td>
  </tr>
  <% end %>
</table>
  • destroyアクションの追加

Userコントローラーにdestroyアクションを追加します。

class UsersController < ApplicationController
  def index
     @users = User.all
  end

  def new
    @user = User.new
  end

  def home
  end

  def edit
    @user = User.find(params[:id])
  end

  def create
    @user = User.new(user_params)

    if @user.save
      redirect_to '/users/index'
    else
      render '/users/new'
    end
  end

  def create
    @user = User.find(params[:id])

    if @user.update
      redirect_to '/users/index'
    else
      render '/users/edit'
    end
  end

  def destroy
    @user = User.find(params[:id])
    @user.destroy
 
    redirect_to users_index_path
  end

  private
    def user_params
      params.require(:user).permit(:name, :password, :password_cofirmation)
    end
end

これでユーザーが削除できるようになりました。削除時のSQLは次のようになっていることがRails severのログから確認できます。

User Destroy (0.9ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 3]]

まとめ

今回でユーザーの編集・削除機能が完成しました。

ログイン機能を満たす為には認証機能を用いて編集や削除できる範囲を自分のユーザーのみにする必要があります。

続きとして認証機能を追加していきたいと思います。

参考文献

Ruby on Rails ガイド

Ruby on Rails チュートリアル