Railsでカスケード削除を設定できますか?


88

これはおそらくインターネットのどこかにあると思いますが、Stackoverflowで答えが見つからないので、ここで知識ベースを少し増やすことができると思いました。

私はRubyand Railsの初心者ですが、私の会社はかなりの投資をしているので、もう少し詳しく知りたいと思っています。

データベースからではなく「モデル」からアプリケーションを設計するという考え方を変えるのは難しいので、データベースのデータベースでこれまで行ってきたすべての設計作業をどのように行うかを考えています。代わりにRailsモデル。

それで、私が自分自身に与えた最新のタスクは、カスケード削除を行うようにRailsデータベースモデルを構成する方法を理解することですか?これを行う簡単な方法はありますか?または、MySqlにアクセスしてこれを設定する必要がありますか?

回答:


103

:dependentオプションを:delete_allに設定することもできます。:delete_allは、単一のSQLステートメントを発行して、すべての子レコードを削除します。このため、:delete_allを使用すると、パフォーマンスが向上する可能性があります。

has_many :memberships, dependent: :delete_all

8
あなたの説明は紛らわしいです。単一のSQLステートメントが使用されますが、destroyメソッドは子行ごとに呼び出されません。そのためにはdestroy_allを使用する必要があります。
ジョントプリー

@ John-編集によって混乱が解消されることを願っています。それを指摘してくれてありがとう。
マイクブリーン

26
使用:delete_allと使用の違いを理解してください:destroy。どちらの場合も、子メンバーシップ(delete [要出典]とndestroy(子に依存するdestroyがある場合)の1レベル)がデータベースから削除されますが、:destroy各子オブジェクトがインスタンス化され、最初にコールバック:delete_allが実行されますが、直接実行されます。データベース内のSQLDELETEステートメント。:destroyそのために遅くなりますが、レコードが破棄されたときにコールバックを行うことができます。一方の端でレールを迂回し、もう一方の端で潜在的なn ^ xインスタンス化。
jstim 2014

2
データベースの外部キーも設定することをお勧めします。そうすれば、1回の操作でレコードが削除されます。私が投稿した以下の回答を参照してください。
ヘンドリック2017年

66

ええ、できます。has_manyのような関係を使用している場合は、これを行うだけです。

has_many :memberships, dependent: :destroy

ダン、それで、私の次の質問は、データベース移行コマンドを実行した場合、それが実際にデータベースに設定されるかどうかだと思います。それとも、カスケードは完全にレールによって処理されますか?
matt_dev 2008

はい、それはレールによって処理されます。(ただし、関連するすべての行を常に削除する必要があることを確認してください。)
Stein G. Strindhaug 2008

@ Matt-has_many行はモデルクラスに含まれている必要があります。移行によって追加されることはありません。
ガレス

依存モデルに別のhas_many関係がある場合にも機能するため、このソリューションを好みます
tpei 2018

25

提供された回答とは反対に、データベースレベルでもこれを行うことを強くお勧めします。異なるプロセスまたはマルチスレッド環境がある場合、レコードが適切に削除されない可能性があります。さらに、データベースの外部キーを使用すると、大量のデータを削除する際の処理が大幅に高速化されます。

提案された答えのようにこれを行います:

has_many :memberships, dependent: :delete_all

ただしforeign_key、移行では必ずを設定してください。そうすれば、データベースが自動的にレコードを削除します。

ユーザーモデルがあると仮定して、メンバーシップが削除されたときに値を無効にするには:

add_foreign_key :users, :memberships, on_delete: :nullify

メンバーシップが削除されるたびに、すべてのモデルを削除することもできます

add_foreign_key :users, :memberships, on_delete: :cascade

したがって、「has_many:memberships、dependent :: delete_all」と「add_foreign_key:users、:memberships、on_delete :: cascade」の両方を使用できますか?それはうまくいくでしょうか?
ルビコン2018年

2
delete_allモデルでを設定する必要もありません。外部キーは、データベースレベルですべてを適切に削除します。
ヘンドリック

3
両方をするとどうなるのか気になります。マイナスの影響はないようですが、ARレベルとDBレベルの両方を実行するというこの方法で悪い経験をした人はいますか?
James Klein

1
データベースレベルは私が探していたものです。これは私の意見では受け入れられた答えであるはずです。他のものは、私のクエリが標準のActiveRecord操作に固執する場合にのみ機能するようです。
ブレット・ビーティ

10

delete_allは、子レコードに対してコールバック(before_destroyやafter_destroyなど)を実行しないことに注意してください。


6

カスケード削除を実際のデータベース構造に反映させたい場合は、このプラグインが探しているものを提供する可能性があるようです。

http://www.redhillonrails.org/foreign_key_migrations.html

移行でこれを使用するための形式は、次のようになります。

create_table :orders do |t|
  t.column :customer_id, :integer, :on_delete => :set_null, :on_update => :cascade
  ...
end

5
そのリンクは無効
gdelfino 2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.