Railsのシンプルなログイン機能 Part3
目次
はじめに
ログイン機能の勉強として機能を細分化しつつ実装します。
理解するための実装なので設計上好ましくない実装が含まれます。できるだけシンプルに実装し、理解し易さを求めたので今回のような実装になりました。ないとは思いますが、後述するコードを参考にする際はお気をつけください。
- 環境
バージョン | |
---|---|
OS | OS X 10.15.6 |
ruby | 2.6.4 |
rails | 6.0.3 |
前回の続きをやっていきます。前回はパスワードの暗号化や登録情報のバリデーションを実装しました。それに次の項目を加えます。
- ユーザー編集
- ユーザー削除
設計
- データベース
カラム | 用途 | データ型 |
---|---|---|
id | 自動生成のID | intger |
name | ユーザーネーム | string |
password_digest | パスワード | string |
機能(追加)
ユーザー編集機能
ユーザー削除機能
ビュー
ファイル名 | 内容 |
---|---|
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]]
まとめ
今回でユーザーの編集・削除機能が完成しました。
ログイン機能を満たす為には認証機能を用いて編集や削除できる範囲を自分のユーザーのみにする必要があります。
続きとして認証機能を追加していきたいと思います。