関連する子テーブルのデータを一度削除して一括で作り直す。という処理を実装した際、削除したはずのデータの情報が残ってしまっていたことがあったので、これにいついて調べた内容をまとめます。
結論
結論を先にお話しすると、アソシエーション経由で取得したデータはキャッシュされるということです。
アソシエーション経由のデータが既に取得済みであった場合、その後削除などをしてから取得し直しても最初に取得したものがキャッシュされているため、reload
や reload_〇〇
などのメソッドを使わないと反映されません。
概要
各部署の人員名簿をCSVから取得してデータを更新する機能を例にします。
テーブルは以下の通りです。
class Department < ApplicationRecord
has_many :members
end
class Member < ApplicationRecord
belongs_to :department
end
CSVをアップロードして内容を取得し、その情報をもとに Department
に紐づくmembers
を作成します。
この際既存のスタッフ情報は一旦削除し、新しく作り直す方法を採用します。
※ CSVのアップロードや情報の取得については本題ではないので割愛します。
一度削除しているのに前のIDが残っている
def update_members(department_id)
department = Department.find(department_id)
members = department.members
# 確認用
puts "before ids --------- #{members.map(&:id)}"
# 一旦紐づくstaffを削除する
members.each(&:destroy)
csv_data.each do |data|
department.members.create!(data)
end
# 確認用
puts "after ids ---------- #{members.map(&:id)}"
end
アソシエーション経由でデータを取得している箇所は members = department.members
この部分です。
上記のメソッドには一通りの処理の前後に確認用で members
のIDを表示する箇所があります。
これを実行すると以下のように表示されるでしょう。
(※登録するmemberの数は5名分だとします)
before ids --------- [1, 2, 3, 4, 5]
after ids ---------- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
一旦削除してから作り直しているので、想定では[6, 7, 8, 9, 10]となっているはずのところ、
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]と消したはずのIDまで表示されてしまっています。
これが以前のデータのキャッシュが残っている状態です。
解決策
アソシエーション経由にしない
Member.where(department_id: department.id).destroy_all
このようにアソシエーションを経由せずに削除をすればキャッシュは残りません。
リロードする
department.members.reload.map(&:id)
上記のように reload
をしてあげると情報を更新できます。
belongs_toの子テーブルの方から参照する場合は、reload_department
というような reload_親テーブル
メソッドが使えます。
今回は以上です。
コメント