【Rails】モデルを削除するときに同時に中間テーブルに存在するレコードも削除するhas_many~dependent: destroy

2018年3月25日

今日も1行のコードを書くのに3時間も費やしてしまいました。

1行書くのに1時間、1行書くのに1時間‥そんな牛歩な私ですが、Twitterで怒りをつぶやきながらなんとかプログラミングスクールで学習しております

あるモデルを削除するときに、他のテーブルにもこのモデルのIDのが存在してる時ってあります。

例えばBookモデル。
Bookモデルにはタイトルとか著者とか発行年月日とかが入ってる。

また本とレビューを関連付ける中間テーブル(BookReview)にもこのbook_idと、投稿されたreview_idなんかが入ってたりします。

レビューテーブル(Review)はまた別で、review_idと、そのレビューを書いたuser_idと、レビューの中身review_contentなどカラムで構成されてたりします。

で、ある本をBooksテーブルから削除しようと思ったら、このBookに紐付いている中間テーブルの行も削除しないといけません。

書籍情報だけ消して、レビュー側も削除しないと宙ぶらりん状態になってしまいます。
そこで私が考えたのが次のようなメソッドです。

Bookモデルのdestroyアクションです

def destroy
  zenbu = BookReview.where(book_id: @book.id) #book_idが3のレコードのインスタンスを全部とってくる

  zenbu.each do |hoge| #レコードのインスタンスを1個ずつ取り出して
    hoge.destroy if hoge  #もし取り出せたら、中間テーブルの方を先に削除
  end #これでbook_idが3のレコードを全部削除できた
  
  @book.destroy #つぎに目的のbookを削除する
  flash[:success] = '書籍情報を削除しました。'
  redirect_back (fallback_location: root_path)
end

これで一応うまくいったのです。すごい俺!よくこんなコード書けたよ。

ところが、こんな面倒なことをせずに1行で実現できメソッドがあったのです!(爆
3時間かけたんですけど‥

それがこの記述です。Bookクラスにhas_manyのdependent: :destroyを入れるんです。

class Book < ApplicationRecord
  has_many :bookreviews, dependent: :destroy

これはどういう意味かというと、Bookを削除するときに、中間テーブルbookreviewsを消してくれるって処理。

え?!これだけ?!

あぁなんてこった。Rubyってこういうの「暗記」っていうか「知ってないと」たどり着けないじゃん。

destroyメソッドを実装するときに、書き方がわからずSQLを直で書きたいと思いながら、あれこれ考えて答えにたどり着いたのに。。さらにその先のdependent destroyなんて実装があったとは。

ぜひ皆さんも参考にしてみてください。