Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - in what order does dependent => destroy follow?

Given this example:

class Server < ActiveRecord::Base
  has_many :clients,:dependent => :destroy 
  after_destroy: delete_server_directory
end

class Client < ActiveRecord::Base
  belongs_to :server

  before_destroy :copy_some_important_stuff_from_the_server_directory_before_its_too_late
end

Will this be the order of destruction when I call server.destroy?

  1. Server#clients, along with Client's before/after_destroy callbacks
  2. Server will be destroyed
  3. followed by the Server's after_destroy callback
like image 994
robodisco Avatar asked Feb 03 '10 11:02

robodisco


People also ask

What does dependent destroy do Rails?

Dependent is an option of Rails collection association declaration to cascade the delete action. The :destroy is to cause the associated object to also be destroyed when its owner is destroyed.

How do you destroy in Rails?

The standard way to delete associated data in Rails is to let ActiveRecord handle it via dependent: :destroy . In the following example, when the parent model ( author ) is deleted, all data in the dependent models will get deleted by ActiveRecord as well. There is an indexed foreign key, but no foreign key constraint.

What is the difference between delete and destroy in Rails?

Rails Delete operation using delete method Unlike the destroy method, with delete, you can remove a record directly from the database. Any dependencies to other records in the model are not taken into account. The method delete only deletes that one row in the database and nothing else.

What does Delete_all return?

If you use delete_all , it will skip all the destroy callbacks for the records that you're deleting (helpful for when you don't want these to run) and it will return the number of records that have been deleted.


1 Answers

You can very easily test. I took your code, and implemented the callbacks with a simple call to puts. Then launched script/console and had ActiveRecord log to the console:

>> ActiveRecord::Base.logger = Logger.new(STDOUT)
=> #<Logger:0x0000000308d2f0 ...>

Set up some basic environment:

>> a = Client.create :name => 'Client 1'
  Client Create (0.4ms)   INSERT INTO "clients" ("name", "server_id") VALUES('Client 1', NULL)
=> #<Client id: 1, name: "Client 1", server_id: nil>
>> b = Client.create :name => 'Client 2'
  Client Create (0.5ms)   INSERT INTO "clients" ("name", "server_id") VALUES('Client 2', NULL)
=> #<Client id: 2, name: "Client 2", server_id: nil>
>> server = Server.create :name => 'The Server'
  Server Create (0.3ms)   INSERT INTO "servers" ("name") VALUES('The Server')
=> #<Server id: 1, name: "The Server">
>> server.clients = [a, b]
  Client Load (0.4ms)   SELECT * FROM "clients" WHERE ("clients".server_id = 1) 
  Client Update (0.4ms)   UPDATE "clients" SET "server_id" = 1 WHERE "id" = 1
  Client Update (0.2ms)   UPDATE "clients" SET "server_id" = 1 WHERE "id" = 2
=> [#<Client id: 1, name: "Client 1", server_id: 1>, #<Client id: 2, name: "Client 2", server_id: 1>]

And here's the gist of it:

>> server.destroy
>>> copy_some_important_stuff_from_the_server_directory_before_its_too_late called!
  Client Destroy (0.5ms)   DELETE FROM "clients" WHERE "id" = 1
>>> copy_some_important_stuff_from_the_server_directory_before_its_too_late called!
  Client Destroy (0.2ms)   DELETE FROM "clients" WHERE "id" = 2
  Server Destroy (0.2ms)   DELETE FROM "servers" WHERE "id" = 1
>>> delete_server_directory called!
=> #<Server id: 1, name: "The Server">

So it looks like you were dead on target. :)

P.S.

  • There's a small syntax error in the server model's after_destroy.
  • I assume with step 1 you really meant before_destroy, as seen in your example.
like image 112
Stéphan Kochen Avatar answered Nov 02 '22 13:11

Stéphan Kochen