2017-10-23 15 views
1

不要なクエリをトリガーすることなく、Railsのhas_many関連付けからレコードを削除するのに問題があります。基本的には、has_manyリレーションを持つモデルがあり、いくつかの基準に基づいて複数のレコードを削除したいと考えています。私はアソシエーションを最新の状態に保ちたいだけでなく、データベースからレコードを削除し、これを行うために1つのDELETEクエリを必要とします。私は新しいオブジェクト(不要なUPDATEクエリを生成する)とdelete_all(1つのクエリを作成するが、関連付けを更新しない)を呼び出すという関係に割り当てようとしました。has_manyからレコードを削除する単一のクエリとのRails関連付け

+0

Railsは 'それぞれが'(before_'をコールバックを実行するために、削除したいオブジェクトを見つける必要があるとafter_' destroy)を実行します。滑らかな斜面であるそのプロセスをスキップしたい場合は、この「すべての関連オブジェクトを削除する」に関するすべてのロジックを保持し、アソシエーションをリセットするサービスオブジェクトを作成したい場合があります。 – MrYoshiji

+0

アソシエーションをリセットすることも最適ではないと思います。後でアソシエーションがアクセスされると、リレーション内に何が含まれるべきかを知っていても、オブジェクトを再取得する必要があるからです。 – mp94

+0

IMOでは、SQLクエリを減らしたり、Railsの動作を再定義したりしないでください。最初の視界では見えませんが、アプリ全体が何ヶ月間もそれを使用していたときに、多くの問題が発生する可能性があります。 – MrYoshiji

答えて

0

リレーションからレコードを削除するには、2つの方法があります。 destroyは、すべての関連レコードを1つずつ削除し、削除されたレコードごとにコールバックを実行します。 delete_allは、1つのクエリ内のすべてのレコードを削除し、コールバックを実行しません。

ので、モデルにあなたが持っている可能性があり:あなたは顧客に

pry(main) foo = Customer.first 
pry(main)> foo.destroy 
    (0.3ms) BEGIN 
    SQL (290.4ms) DELETE FROM `statements` WHERE `statements`.`customer_id` = 3 
    SQL (2.6ms) DELETE FROM `customers` WHERE `customers`.`id` = 3 

すべてが1うねりfoopで行わを削除すると

class Customer < ApplicationRecord 
    has_many :statements, dependent: :delete_all 

をして、にはコールバックは削除されません。

か -

class Customer < ApplicationRecord 
    has_many :statements, dependent: :destroy 

、あなたが顧客に

pry(main) foo = Customer.first 
pry(main)> foo.destroy 
    (0.4ms) BEGIN 
    Statement Load (25.0ms) SELECT `statements`.* FROM `statements` WHERE `statements`.`customer_id` = 4 
    SQL (0.5ms) DELETE FROM `statements` WHERE `statements`.`id` = 9023 
    SQL (0.3ms) DELETE FROM `statements` WHERE `statements`.`id` = 9024 
    SQL (0.3ms) DELETE FROM `statements` WHERE `statements`.`id` = 9025 
    . . . etc etc etc . . . 

を削除すると、各従属レコードは一度に一つ、各削除で実行するコールバックを削除しました。

delete_allおよびdestroyは、同様の効果を持つ結果セットで実行できます。あなたは関連レコードにいくつかのフィルタを持っていると思ったのであれば:

pry(main) foo = Customer.first 
pry(main)> bar = foo.statements.where(some_param: 42) 
pry(main)> bar.delete_all 
    SQL (4.2ms) DELETE FROM `statements` WHERE `statements`.`customer_id` = 7 AND `notices`.`some_param` = 42 
=> 2 

か -

pry(main) foo = Customer.first 
pry(main)> bar = foo.statements.where(some_param: 42) 
pry(main)> bar.destroy_all 
    (0.2ms) BEGIN 
    SQL (0.6ms) DELETE FROM `notices` WHERE `notices`.`id` = 4639 
    (0.5ms) COMMIT 
    (0.2ms) BEGIN 
    SQL (0.5ms) DELETE FROM `notices` WHERE `notices`.`id` = 4640 
    (0.4ms) COMMIT 
    (0.1ms) BEGIN 
    SQL (0.5ms) DELETE FROM `notices` WHERE `notices`.`id` = 4641 
    (0.5ms) COMMIT 
    . . . etc etc etc . . . 
+0

' foo.statements.where(some_param:42).delete_all'のようなことをすれば、 、 'foo.statements'はもはや実際にDBにあるものではありません。 – mp94

+0

この場合、reload文は 'foo.statements.reload'です。 – rbb

関連する問題