Rails 6.0でアプリを開発 基本の流れ⑨ 情報の更新や削除
今回はユーザー情報の更新や削除の機能、管理者の機能を実装するためのメモ
実現したいこと
ユーザー情報を更新できるのはそのユーザー自身。そのすみわけと、ユーザーを削除できるのは管理者のみ。という機能の実装。
1)ユーザー情報の更新
ユーザー情報をそのユーザー自身のみ更新できるようにするには、承認機構とbeforeフィルタを使って実装する。
①Usersコントローラーにeditアクションを追加。
params[:id]でそのユーザーのIDを見つける。
②editアクションに対応するviewの作成
編集の項目を作る。
※仕組み補足
③headerのリンクを更新
この時current_userヘルパーメソッドを使用することで現在ユーザーの編集画面に移行
④newとeditの共通部分をパーシャル化する
ⅰ)パーシャルの作成
form_for部分をパーシャルにまとめる
ボタン内の文言は実際のページからprovideで送りyieldで受け取る
ⅱ)新規登録フォームからフォーム部分を抜く
ボタン内の文言を送る
renderでフォーム部分を表示
ⅲ)編集フォームからフォーム部分を抜く
ボタン内の文言を送る
renderでフォーム部分を表示
⑤updateアクションの作成
更新はupdate_attribute(user_params)を使用。
条件付きで成功時と失敗時の挙動を記述。
2)統合テストでチェック
$ rails g integration_test users_edit
①編集に失敗するテスト
エラー時の表示もテスト
エラー情報
DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead)
update_attributesがupdateに代わります。
これでエラーは出なくなった
②編集に成功するテスト
駆動開発として上記がパスするように設定
ⅰ)updateアクションにフラッシュメッセージを入れ、ユーザーページにリダイレクトさせる。
ⅱ)パスワードを更新しなくてもいいように空だった時に例外処理を入れる。
allow_nil: true
※新規登録時はhas_secure_passwordでオブジェクト生成時に存在性を検証しているため問題なし
3)認証と認可
認証 サイトのユーザーを識別する(authentication)
認可 そのユーザーが実行可能な操作を管理(authorizaiton)
編集ではユーザーにログインを要求かつ、自分以外のユーザー情報を更新できないように制御する必要あり
・ログインしていないユーザーからの保護として
→ログインページへ転送+メッセージを表示
・ログイン済みだが許可されていないページへアクセスしようとすることから保護
→ルートへリダイレクト
①beforeフィルターと対応するメソッドを作成し、onlyオプションで適用範囲を制限
この変更に伴い、users_edit_testの両テストで最初にログインしておくように設定しなおしておく。(log_in_asを使用)
②ログインしていないユーザーがリダイレクトさせられるかチェックするテスト
③自分以外の情報を編集できないようにする
ⅰ)fixtureファイルに二人目のユーザーを追加
ⅱ)テストに二人目のユーザーを追加し間違ったユーザーが編集しようとしたときのテストを追加とbeforeフィルターと対応メソッドを作成
beforeフィルターをかけ、正しいユーザーかどうか確認させる
ⅲ)current_user?(user)ヘルパーメソッドを作成
ⅳ)ヘルパーメソッドを使ってcorrect_userメソッドを書き換え
4)フレンドリーフォーワーディング
ログインしていないユーザーがログインページへ飛ばされた後、ログインしなおした際にもともと入ろうとしたページに飛ばす
①フレンドリーフォーワーディングのテスト
②フレンドリーフォーワーディングの実装
ⅰ)session_helper.rbに下記メソッドを作成
・store_locationメソッド
リクエスト時のページを保存するメソッド
・redirect_back_orメソッド
その場所にリダイレクトさせるメソッド
※ブラウザに記憶させるのでsession変数を使用
※Getリクエストを送られたURLをsessionのforwarding_urlに保存
ⅱ)ログインユーザー用beforeフィルターにstore_locationを追加
ⅲ)ログインのcreateアクションにフレンドリーフォーワーディング機能実装
ⅳ)session上に保存したurlが削除されフレンドリーフォーワーディングが有効なのは一度だけになっているかテスト
4)ユーザー一覧ページの作成
indexで表示。ログインしたユーザーにしか見えないようにする。
①ログインしていないユーザーがアクセスしたときに、indexアクションにリダイレクトするかテスト
②indexアクションにログインを要求する
・beforeフィルター(logged_in_user)にindexアクションを追加
・indexアクションを作成
・すべてのユーザーを表示させる変数を作成
③indexビューの作成(ユーザーの一覧ページ)
④スタイルの編集
⑤トップページのリンクを全部テストでチェックしてみる
5)サンプルユーザーを追加する
①サンプルユーザーを使用するために、GemfileにFaker gemを追加する
※bundle install
②seedsファイルでサンプルユーザーを生成する
③DBないのデータをいったんリセットしSeeds内のデータを追加
$ rails db:migrate:reset
$ rails db:seed
※エラーが出た場合、それに従う
6)ページネーション
①Gemfileにkaminariを追加
※bundle install
②viewでページネーションを行うようにRailsに指示
③indexアクションをページネーション用に編集
・allをpageメソッドに
・:pageパラメーターに使われるparams[:page]はkaminariによって自動的に生成
④テスト用にfixtureに30人ユーザーを追加する
⑤統合テストファイルを作成する
$ rails g integration_test users_index
7)リファクタリング
①index.html.erbでユーザー一覧のliタグをrender呼び出しに変更
この部分を、
こうする。renderをパーシャルではなくてUserクラスのuser変数に対して行う。
自動的に_user.html.erbを探しに行く
②_user.html.erbパーシャルを作成
③さらにリファクタリング
この部分を、
インスタンス変数に対してrenderを直接実行するようにする。
自動的に@usersをUserオブジェクトのリストと推測してくれ、それぞれのユーザーを列挙し出力してくれる。
8)管理ユーザーの作成
①admin属性をUserモデルに追加
$ rails g migration add_admin_to_users admin:boolean
②デフォルトでは管理者になれないようにする
default: falseを追加で記述
$ rails db:migrate
③seedファイルで最初のユーザーを管理者にする
④DBをリセットしサンプルデータを再度生成する
$ rails db:migrate:reset
$ rails db:seed
⑤admin属性の変換が禁止されていることをテスト
StrongParametersにadminが入っていないのでadminは更新されない。
9)ユーザーの削除
①indexページにユーザー削除用のリンクを追加。
リンクの生成を行っているのは method: :deleteの部分。
条件分岐でadminユーザーのみに削除リンクを表示させるようにする。
②destroyアクションの追加
・destroyアクションもログインを要するbeforeフィルターで追加
・admin_userメソッドとbeforeフィルターを設置し管理者だけに限定
③ユーザー削除のテスト
ⅰ)fixture内の一人を管理者に
ⅱ)管理者権限の制御をテスト(コントローラー)
・ログインしなければ削除できない
・管理者でなければ削除できない
ⅲ)indexページで削除リンクとユーザー削除に対する統合テスト
長かったがここまでで情報更新、削除、管理者の設定が完了
参考にさせていただいたサイト
第10章 ユーザーの更新・表示・削除 - Railsチュートリアル
Ruby on Rails チュートリアル 第10章 ユーザー更新 beforeフィルター フレンドリーフォワーディング adminまで - Qiita