読者です 読者をやめる 読者になる 読者になる

Aqutras Members' Blog

株式会社アキュトラスのメンバーが、技術情報などを楽しく書いています。

Railsのbelongs_toのdestroyとdeleteとdelete_allの違いを調べました

先日railsのモデルを追加していた時に,belongs_toのオプション:dependentについて調べました. 特にdestroydelete_alldeleteの違いがわからなくなったのでまとめておきます.

結論

  • has_manyの時に使うのがdestroydelete_all
  • has_oneの時に使うのがdestroydelete

  • deletedelete_allはそれだけを消す

  • destroyは子クラスの:dependentも処理する

  • 関連を消す必要がないなら,delete_allのほうが効率がいい

ちなみに

  • destroy_allはActiveRecordのメソッドとしてはありますが,:dependentには指定できません.

destroy_all (ActiveRecord::Relation) - APIdock

以下実際にrails consoleで試してみた

テストに使ったクラス

# 親クラス
class Parent < ActiveRecord::Base
  has_many :children, dependent: :destroy or delete_all or delete # <- ここを変えてます
end

# 子クラス
class Child < ActiveRecord::Base
  belongs_to :parent
  has_many :grandchild, dependent: :destroy
end

# 孫クラス
class Grandchild < ActiveRecord::Base
  belongs_to :child
end

親クラスのデータを1件,小クラスを2件,孫クラスを2件×2 作成してテストしました.

dependent: :deleteのとき

has_manyなので,エラーが出ます.

ArgumentError: The :dependent option must be one of [:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception], but is :delete

dependent: :delete_allのとき

[2] pry(main)> Parent.first.destroy
  Parent Load (0.1ms)  SELECT  "parents".* FROM "parents"  ORDER BY "parents"."id" ASC LIMIT 1
   (0.0ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "children" WHERE "children"."parent_id" = ?  [["parent_id", 1]]
  SQL (0.1ms)  DELETE FROM "parents" WHERE "parents"."id" = ?  [["id", 1]]
   (1.2ms)  commit transaction
=> #<Parent:0x007f1c583b6b60
 id: 1,
 created_at: Wed, 20 Apr 2016 13:20:16 UTC +00:00,
 updated_at: Wed, 20 Apr 2016 13:20:16 UTC +00:00>

SQLを見ると,関連するクラスについて,一致するデータをまとめて消しています.

dependent: :destroyのとき

[14] pry(main)> Parent.first.destroy
  Parent Load (0.1ms)  SELECT  "parents".* FROM "parents"  ORDER BY "parents"."id" ASC LIMIT 1
   (0.0ms)  begin transaction
  Child Load (0.0ms)  SELECT "children".* FROM "children" WHERE "children"."parent_id" = ?  [["parent_id", 1]]
  Grandchild Load (0.0ms)  SELECT "grandchildren".* FROM "grandchildren" WHERE "grandchildren"."child_id" = ?  [["child_id", 1]]
  SQL (0.1ms)  DELETE FROM "grandchildren" WHERE "grandchildren"."id" = ?  [["id", 1]]
  SQL (0.0ms)  DELETE FROM "grandchildren" WHERE "grandchildren"."id" = ?  [["id", 2]]
  SQL (0.0ms)  DELETE FROM "children" WHERE "children"."id" = ?  [["id", 1]]
  Grandchild Load (0.0ms)  SELECT "grandchildren".* FROM "grandchildren" WHERE "grandchildren"."child_id" = ?  [["child_id", 2]]
  SQL (0.0ms)  DELETE FROM "grandchildren" WHERE "grandchildren"."id" = ?  [["id", 3]]
  SQL (0.0ms)  DELETE FROM "grandchildren" WHERE "grandchildren"."id" = ?  [["id", 4]]
  SQL (0.0ms)  DELETE FROM "children" WHERE "children"."id" = ?  [["id", 2]]
  SQL (0.1ms)  DELETE FROM "parents" WHERE "parents"."id" = ?  [["id", 1]]
   (0.7ms)  commit transaction
=> #<Parent:0x007f1c57edd558
 id: 1,
 created_at: Wed, 20 Apr 2016 15:06:31 UTC +00:00,
 updated_at: Wed, 20 Apr 2016 15:06:31 UTC +00:00>

検索をかけた後,一番深い関連から1件ずつ消しています.