1
0

fields_forを使って親子関係にあるモデルのレコードを一度に編集・削除する

Last updated at Posted at 2024-03-09

はじめに

この記事ではポートフォリオ作成中に学習したことを自分のために記録しています。
初学者のため理解が不十分なところがあるかもしれません。
その場合はご指摘いただけると幸いです。

やりたいこと

  • 親子関係のあるモデルのレコードを一度に編集・削除したい

YouTubeのブックマークアプリを作成しているので、ブックマーク(親)とそれに紐づくタイムスタンプ(子)を1つのフォームで編集・削除できるようにしていきます。
ブックマークとタイムスタンプは一対多の関係です。

完成イメージはこんな感じ
BF1615E1-419E-4E9B-9051-03853492B71B.png

いざ実装

子モデルの編集

accepts_nested_attributes_for⁠メソッドを親モデルに追加

app/models/bookmark.rb
  has_many :timestamps
  accepts_nested_attributes_for :timestamps #追加

編集フォーム作成

app/views/bookmarks/edit.html.erb
<%= form_with model: @bookmark do |f| %>
     <%= f.label :url, "URL" %>
     <%= f.text_field :url %>

     <%= f.label :is_public, "おすすめ動画として公開する" %>
     <%= f.check_box :is_public %>

     <%= f.hidden_field :user_id, value: @user.id %>

       <%= f.fields_for :timestamps do |timestamp| %>  #ここから子モデルの編集フォーム
         <%= timestamp.number_field :hour %>
         <%= timestamp.label :hour, "時間" %>

         <%= timestamp.number_field :minute %>
         <%= timestamp.label :minute, "分" %>

         <%= timestamp.number_field :second %>
         <%= timestamp.label :second, "秒" %>

         <%= timestamp.label :comment, "メモ" %>
         <%= timestamp.text_field :comment %>

         <%= timestamp.hidden_field :bookmark_id, value: @bookmark.id %>
       <% end %>

     <%= f.submit "登録" %>
   <% end %>

fields_for内でソートしたいとき

上記フォームで入力した時間(hour)・分(minute)・秒(second)を基に作成したタイムスタンプをコントローラ側で秒に換算し、start_timeとして保存しています。
編集フォームでタイムスタンプをstart_time順にソートしたかったため、fields_forの第2引数を追加して下記のような記述にしました。

<%= f.fields_for :timestamps, @bookmark.timestamps.sort_by(&:start_time) do |timestamp| %

コントローラにストロングパラメータを設定

app/controllers/bookmarks_controller.rb
  def bookmark_params
    params.require(:bookmark).permit(
      :user_id,
      :url,
      :description,
      :is_public,
      :video_id,
      timestamps_attributes: [:id, :bookmark_id, :hour, :minute, :second, :start_time, :comment] #この部分を追記
    )
  end

ストロングパラメータを追加します。

ここで重要なのが、子モデルのパラメータに:idを入れておくことです。
これを忘れてしまうと編集する度に重複するレコードが作成され、子モデルのレコード数がねずみ算的に増えてしまいます。
パラメータにidが含まれている場合は既存のレコードだと判断されupdateが実行されますが、idが含まれていないと新しいレコードだと判断されcreateが実行される…ということのようです。

以上で子モデルのレコードが編集できるようになりました!

子モデルの削除

編集だけでなく削除もできるようにしていきます。

accepts_nested_attributes_forにallow_destroy: trueを渡す

app/models/bookmark.rb
accepts_nested_attributes_for :timestamps, allow_destroy: true

フォームに_destroyの入力欄を追加

子モデルの_destroyキーの値がtrueまたは1であればレコードが削除されます。
Railsガイドの例にならいチェックボックスを追加しました。

app/views/bookmarks/edit.html.erb
<%= timestamp.check_box :_destroy %>

ストロングパラメータに_destroyを追加

app/controllers/bookmarks_controller.rb
 def bookmark_params
    params.require(:bookmark).permit(
      :user_id,
      :url,
      :description,
      :is_public,
      :video_id,
      timestamps_attributes: [:id, :bookmark_id, :hour, :minute, :second, :start_time, :comment, :_destroy] #:_destroyを追加
    )
  end

以上で子モデルのレコード削除もできるようになりました!

最後に

思った通りに動いてくれないことも多く大変でしたが、binding.pryでひたすらparamsの値を見ながら進めたことで少しは理解が深まったのではないかな…という気がします。

この記事がどなたかの参考になれば幸いです。
お読みいただきありがとうございました。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0