Kalpit
Kalpit Full stack developer working on Ruby on Rails and React

Delete VS Destroy in Rails

Delete VS Destroy in Rails

In this blog, we are going to see the difference between delete and destroy methods in rails.

Let’s take an example where we have following models: User, Post, Comment

1
2
3
4
5
6
7
8
# app/models/user.rb

class User < ApplicationRecord
  self.inheritance_column = :_type_disabled

  has_many :posts, dependent: :destroy
  has_many :comments, through: :posts
end
1
2
3
4
5
6
7
# app/models/post.rb

class Post < ApplicationRecord
  belongs_to :user

  has_many :comments, dependent: :destroy
end
1
2
3
4
5
# app/models/comment.rb

class Comment < ApplicationRecord
  belongs_to :post
end
1
2
3
4
5
6
7
8
3.0.3 :067 > User.count   #=> 10
  User Count (1.0ms)  SELECT COUNT(*) FROM "users"

3.0.3 :068 > Post.count   #=> 7
  Post Count (0.5ms)  SELECT COUNT(*) FROM "posts"

3.0.3 :069 > Comment.count   #=> 12
  Comment Count (0.6ms)  SELECT COUNT(*) FROM "comments"

Destroy:

Destroy method erase record from table. Also, it will erase all the dependent records as well. Because of this functionality, destroy is time consuming as compared to delete method.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.0.3 :070 > User.first
  User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<User:0x000000010cdd67a8                                                     
 id: 2,                                                                          
 email: "micah@fisher.co",                                                       
 password: "[FILTERED]",                                                         
 name: "Curt Mertz Ret.",                                                        
 type: "simple",                                                                 
 created_at: Sat, 04 Feb 2023 17:14:59.737597000 UTC +00:00,                     
 updated_at: Sat, 04 Feb 2023 17:14:59.737597000 UTC +00:00>

3.0.3 :071 > User.first.posts.count   #=> 3
  User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Post Count (1.3ms)  SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = $1  [["user_id", 2]]

3.0.3 :072 > User.first.comments.count   #=> 5
  User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Comment Count (0.5ms)  SELECT COUNT(*) FROM "comments" INNER JOIN "posts" ON "comments"."post_id" = "posts"."id" WHERE "posts"."user_id" = $1  [["user_id", 2]]

If we destroy user then output will be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3.0.3 :075 > User.first.destroy
  User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
  TRANSACTION (0.1ms)  BEGIN                                                              
  Post Load (0.3ms)  SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = $1  [["user_id", 2]]
  Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = $1  [["post_id", 2]]
  Post Destroy (0.5ms)  DELETE FROM "posts" WHERE "posts"."id" = $1  [["id", 2]] 
  Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = $1  [["post_id", 3]]
  Comment Destroy (0.3ms)  DELETE FROM "comments" WHERE "comments"."id" = $1  [["id", 2]]
  Comment Destroy (0.2ms)  DELETE FROM "comments" WHERE "comments"."id" = $1  [["id", 3]]
  Comment Destroy (0.1ms)  DELETE FROM "comments" WHERE "comments"."id" = $1  [["id", 4]]
  Post Destroy (0.1ms)  DELETE FROM "posts" WHERE "posts"."id" = $1  [["id", 3]] 
  Comment Load (0.1ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = $1  [["post_id", 4]]
  Comment Destroy (0.3ms)  DELETE FROM "comments" WHERE "comments"."id" = $1  [["id", 5]]
  Comment Destroy (0.2ms)  DELETE FROM "comments" WHERE "comments"."id" = $1  [["id", 6]]
  Post Destroy (0.1ms)  DELETE FROM "posts" WHERE "posts"."id" = $1  [["id", 4]] 
  User Destroy (0.2ms)  DELETE FROM "users" WHERE "users"."id" = $1  [["id", 2]] 
  TRANSACTION (1.0ms)  COMMIT

See in above example, all the dependent records i.e. posts and comments gets also erased from table in case of destroy method.

After destroying user:

1
2
3
4
5
6
7
8
3.0.3 :076 > User.count   #=> 9
  User Count (0.6ms)  SELECT COUNT(*) FROM "users"

3.0.3 :077 > Post.count   #=> 4
  Post Count (0.6ms)  SELECT COUNT(*) FROM "posts"

3.0.3 :078 > Comment.count   #=> 7
  Comment Count (0.5ms)  SELECT COUNT(*) FROM "comments"

Delete:

Delete method simply deletes the record in row. Unlike destroy, delete does not erase dependent records in table. Because of this, delete is faster as compared to destroy method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3.0.3 :083 > User.last
  User Load (0.5ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<User:0x0000000107b6f668                                
 id: 11,                                                    
 email: "crissy.mohr@homenick-schuster.biz",                
 password: "[FILTERED]",                                    
 name: "Margarite Ondricka",                                
 type: "simple",                                            
 created_at: Sat, 04 Feb 2023 17:14:59.762022000 UTC +00:00,
 updated_at: Sat, 04 Feb 2023 17:14:59.762022000 UTC +00:00>

3.0.3 :084 > User.last.posts.count   #=> 3
  User Load (0.7ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Post Count (0.4ms)  SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = $1  [["user_id", 11]]

3.0.3 :085 > User.last.comments.count   #=> 6
  User Load (0.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Comment Count (0.4ms)  SELECT COUNT(*) FROM "comments" INNER JOIN "posts" ON "comments"."post_id" = "posts"."id" WHERE "posts"."user_id" = $1  [["user_id", 11]]

Let’s see the output when we delete above ☝🏼 user:

1
2
3
4
5
6
7
8
9
10
11
3.0.3 :086 > User.last.delete
  User Load (1.3ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1  [["LIMIT", 1]]
  User Destroy (1.5ms)  DELETE FROM "users" WHERE "users"."id" = $1  [["id", 11]]     
=> #<User:0x000000010bec91e8                                                    
 id: 11,                                                                        
 email: "crissy.mohr@homenick-schuster.biz",                                    
 password: "[FILTERED]",                                                        
 name: "Margarite Ondricka",                                                    
 type: "simple",                                                                
 created_at: Sat, 04 Feb 2023 17:14:59.762022000 UTC +00:00,                    
 updated_at: Sat, 04 Feb 2023 17:14:59.762022000 UTC +00:00>

Note that only user gets deleted. All the dependent tables i.e. post and comments are present in the system.

1
2
3
4
5
6
7
8
3.0.3 :087 > User.count   #=> 8
  User Count (0.5ms)  SELECT COUNT(*) FROM "users"

3.0.3 :088 > Post.count   #=> 4
  Post Count (0.5ms)  SELECT COUNT(*) FROM "posts"

3.0.3 :089 > Comment.count   #=> 7
  Comment Count (0.8ms)  SELECT COUNT(*) FROM "comments"

If we try to access deleted user from dependent table (post or comment) then, we got nil as result.

Example:

1
2
3
3.0.3 :092 > Post.last.user   #=> nil
  Post Load (0.4ms)  SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT $1  [["LIMIT", 1]]
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 11], ["LIMIT", 1]]

P.S:- Now that we have understood the difference between destroy and delete, use them as per requirement 💣. Do not use destroy if there is no necessity 💥.

Stay tune for upcoming blog explaining how to soft delete record(s) in Rails.

comments powered by Disqus