掲示板の編集、削除機能の実装
掲示板編集ページの作成
フォーム部分はパーシャルを用意して、新規作成ページと共有できるようにしておく ので、今回編集ページのビューは以下のようになる
#boards/edit.html.erb <div class="container"> <div class="row"> <div class="col-lg-8 offset-lg-2"> <h1><%= t('.title') %></h1> <%= render 'form', { board: @board } %> #掲示板フォームのパーシャル </div> </div> </div>
現在ログインしているユーザーのidと掲示板のuser_idが同じ場合編集、削除アイコンを表示させる。まず、この判定を行うメソッドをuserモデルのインスタンスメソッドとして記述しておく
#user.rb def own?(object) id == object.user_id end
ビューに直接ifなどを使って判定してもいいが、userモデルに判定のロジックを記載することで、ロジックを見直したりしたいときなどにuserモデルを見るだけで済む。また引数にobjectを受け取るようにすることで、掲示板だけでなく、コメントなどユーザーに他の関連づいたインスタンスの判定も行えるようにしている。 ビューはこのメソッドを使うことで以下のようになる
<% if current_user.own?(board) %> <%= link_to edit_board_path(board), id: 'button-edit-#{board.id}' do %> <%= icon 'fa', 'pen' %> <% end %> <%= link_to '#', id: 'button-delete-#{board.id}', method: :delete, data: {confirm: ''} do %> <%= icon 'fas', 'trash' %> <% end %> <% end %>
edit,update,destroyアクションの作成 先にコードを記載すると以下のようになる
before_action :set_board, only: %i[edit update destroy] def edit; end def update if @board.update(board_params) redirect_to board_path(@board), success: t('.success') else flash.now[:danger] = t('.fail') render :edit end end def destroy @board.destroy! redirect_to boards_path, success: t('.success') end private def set_board @board = current_user.boards.find(params[:id]) end
今回は,edit,update,destroyアクションにおいて、ルーティングのboardオブジェクトのidから現在のユーザーに関連付いたBoardオブジェクトを取得してプロセスが共通なので、コールバック(オブジェクトに対して、特定のアクションを実行した瞬間に呼び出されるメソッドのこと)としてprivateに登録してある。
privateに登録するのは記載したクラスの外から呼び出されて、悪用されるのを防ぐため
before_action :set_board, only: %i[edit update destroy]の記述によりedit,update,destroyアクションの実行前にset_boardアクションが実行される
確認ダイアログの表示
削除アイコンは
<%= link_to board_path(board), id: 'button-delete-#{board.id}', method: :delete, data: {confirm: ‘よろしいですか?’} do %>
と記述method: :deleteによってHTTPにDELETEリクエストを発行してくれるこの時
HTTPはDELETEリクエストを受け取ることができないので,Rails側はJavascriptを使って偽造してくれる。つまりjavascriptがオフになっていると削除のリンクも無効になってしまうということ。また、リンクやフォームにdata-confirm属性を追加することで、確認ダイアログを表示してくれる。confirm: に表示したい文字列を追加する
また、destroyアクションでdestroyメソッドではなくdestroy!メソッドを使っているのはデータを削除するとき失敗する想定(バリデーションなど)に引っかかるなどを今回の仕様では想定していないため、万が一削除の処理に失敗した場合には処理を中断させて例外として扱う必要があるためである。
参考文献