A note of a person who is learning programming, SakaTaQ

ロック好きのプログラミング学習

画像複数投稿で必要だったメソッドのオプション、その他確認したこと

前回の続き

dependent: :destroy

アソシエーションの記述であるhas_manyやbelongs_toなどの後に書くオプション。
関連するレコードを同時に削除できる。

class User < ApplicationRecord
  has_many :items, dependent: :destroy
end
class Item < ApplicationRecord
  belongs_to :user
end

こういった構成になっていれば、例えばユーザーが退会した時にusersテーブルからそのユーザーの情報(レコード)が消えるとそれに関連しているレコード、ここでいうなら出品している商品の情報も同時に削除される、ということ。
ログアウトした時とかdestroyアクション動いてる気がするけど、多分それは関係ない...確かめたわけじゃないけど、deviseはsessionだのregistrationだの色々コントローラーがあるので、sessionのdestroyの時はdependentは動かないとかそんな感じだと思う。


allow_destroyオプション

accepts_nested_attributes_forを使用した際に記述したオプション。
nested_attributesなレコードを一緒に削除してくれる。allow_destroy: trueの形で使う。
今回で言うとItemモデルに対してImageモデルはnested_attributesなので、Itemモデルのレコードが削除された時に関連しているImageモデルのレコードも削除される。この時、対象に{_destroy: 1}のように渡される。
削除する際にストロングパラメーターにて以下の記述が必要。


images_attributes: [:name, :_destroy, :id]

コントローラーのストロングパラメータにて
permit(:name, ..., images_attributes: [:name, _:destroy, :id])のように記述。
モデル名s_attributes: [:同時に保存を許可するモデルのカラム名]みたいな感じ。
保存するだけなら[:_destroy, :id]はいらない。でも更新とか削除するなら必要。
editアクションなどのfields_forで:imagesを呼ぶと、form_withで呼び出された:itemsに関連している子モデルのレコードの分、fields_forは生成される。
submitして送信した際にターミナルで確認したのだが、それぞれ{id: xx}のような形であることが見れたので、fields_forから受け取ったオブジェクトにメソッドを使用することで、その情報が入っているフォームヘルパーが生成されているのではないかと思っている。(...書いててよく分からんくなってきた💦)

fields_for自体がオブジェクトの分だけ生成されるのが分からなくて、最初はコントローラーでインスタンスを用意してそれを使用していたので画像が5枚の商品でeachをかけて表示させた時に25枚になってしまったとかいい思い出。
後、何だか途中からfields_forのことっぽくなっちゃったのはご愛嬌😌


ストロングパラメーター

params.require(:item).permit(:name, :description, ...).merge(user_id: current_user.id)のように記述する。
Railsではセキュリティ対策として、ストロングパラメーターを使用することでテーブルの内容を保存したり変更をしたりする際に、記述したものだけを保存しそれ以外の情報は許可しないようにする仕組みがある。
form_withから送信されコントローラーが受ける値はハッシュ形式になっており、{}で囲われているのだが、params自体が{}の形式で受け取っているため、そのままでは{}の中に{}がある状態になってしまい、参照することができない。
その為にrequireを使用している。()の中にはモデル名をシンボル形式で指定している。
permitではその後に続く()の中に記述されたattributesの変更を許可している。
これまでの自分の認識ではpermitの中に記述するのは「カラム名」だったわけだけど、images_attributes:などのように複数のモデルを同時に保存するための記述によりimagesテーブルの:nameカラムもattributesの1つとして同時に保存するための許可をすることができる、と言うことを知ったのでここに記述しているのはattributesとして扱うものを記述するという認識でいる。(厳密には違うのかもしれないが誰かに答えを聞いたわけではないのであってるかどうかは知らない)
因みに実際に書いていたストロングパラメータは

params.require(:item).permit(:name, :price, :description, :category_id, :status, :condition, :size, :ship_price, :ship_area, :ship_day, :ship_method, :brand_id, item_images_attributes: [:image_url, :_destroy, :id]).merge(user_id: current_user.id)

モデル名に_を使用したため分かりにくくなったのもいい思い出。


persisted

ActiveRecord::Baseから継承されているインスタンスが使用できるメソッドで、レコード内容を更新する際に使用した。
@item.persisted?のように書くことで、インスタンスに代入されたレコード情報がデータベースに保存済みかそうでないかを確認、trueやfalseの真偽値を返す。 if文にそのまま上記の記述を突っ込むことで条件文を作成できる。

= f.fields_for :item_images do |image|
   (省略)
      = image.label :name do
        編集
        = image.file_field :name
      .buttons--delete 削除
  - if @item.persisted?
    = image.check_box :_destroy

ざっくりとした構成はこんな感じで削除ボタンを押した時に、(省略)あたりのdivタグを削除するようにJavaScript書いてた。
checkboxはimageオブジェクトから生成され、:_destroyを設定。チェックされてsubmitすることでRailsが該当する:idを検索しそのレコードを削除する仕組み。
気をつけたこととして、checkboxがこのdivタグの中にある場合、削除ボタンでcheckbox自体が同時に消失してしまうと画像を消せなくなってしまう(チェックしたことにならなくなる)。
その為、チェックボックスはdisplay: noneにしておき、削除ボタンが押された時に割り振っておいたチェックボックスのindexを取得し、そのindexが振られたチェックボックスを.propでcheckedするように記述。 それと同時に(省略)のプレビュー用のdivタグを削除することで添付した画像自体が削除されたように見える。
この時、新しく画像を挿入してもそちらとは受け渡し方が違うのかバッティングはしなかった。
この部分に関しては記事書いてる時点では思い出せない。多分ターミナルの情報は確認したと思うんだけど...


今回はここまで。
当時の振り返りを記事にしようって気付いたのが随分後だったので、今になってスクショとか撮っとけばよかったなとか思ってる😓
次はカテゴリ機能の事でも。担当してないけど見て分かる範囲のことを記憶が新しい内に残しておきたい。

したらな❗️ 👋