Dependent Options
Given:
class User < ApplicationRecord
has_many :posts, dependent: XXXXXXX
end
class Post < ApplicationRecord
belongs_to :user
end
Let's see what happens when using the existing dependent options.
destroy
irb(main):002:0> u.destroy
TRANSACTION (0.1ms) begin transaction
Post Load (1.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ? [["user_id", 1]]
Post Destroy (0.4ms) DELETE FROM "posts" WHERE "posts"."id" = ? [["id", 1]]
Post Destroy (0.1ms) DELETE FROM "posts" WHERE "posts"."id" = ? [["id", 2]]
User Destroy (0.1ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 1]]
TRANSACTION (0.7ms) commit transaction
=> #<User id: 1, name: "John", email: "some@email.com", created_at: "2021-04-10 13:39:08.099961000 +0000", updated_at: "2021-04-10 13:39:08.099961000 +0000">
delete_all
:delete => u.destroy will call u.posts.delete (callbacks no executed)
irb(main):002:0> u.destroy
TRANSACTION (0.1ms) begin transaction
Post Destroy (0.6ms) DELETE FROM "posts" WHERE "posts"."user_id" = ? [["user_id", 1]]
User Destroy (0.1ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 1]]
TRANSACTION (1.0ms) commit transaction
=> #<User id: 1, name: "John", email: "some@email.com", created_at: "2021-04-10 13:17:09.423794000 +0000", updated_at: "2021-04-10 13:17:09.423794000 +0000">
destroy_async
It is supposed to delete posts in an async job but for my case this was the behavior:
irb(main):002:0> u.destroy
TRANSACTION (0.1ms) begin transaction
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ? [["user_id", 1]]
User Destroy (0.7ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 1]]
TRANSACTION (0.5ms) rollback transaction
Traceback (most recent call last):
1: from (irb):2
ActiveRecord::InvalidForeignKey (SQLite3::ConstraintException: FOREIGN KEY constraint failed)
nullify
:nullify => user.destroy will try to user.posts.each { |p| p.user = nil } (callbacks no executed)
Will raise an error if column is not nullable
irb(main):002:0> u.destroy
TRANSACTION (0.1ms) begin transaction
Post Update All (0.6ms) UPDATE "posts" SET "user_id" = ? WHERE "posts"."user_id" = ? [["user_id", nil], ["user_id", 1]]
TRANSACTION (0.1ms) rollback transaction
Traceback (most recent call last):
1: from (irb):2
ActiveRecord::NotNullViolation (SQLite3::ConstraintException: NOT NULL constraint failed: posts.user_id)
restrict_with_exception
:restrict_with_exception => u.destroy will do raise ActiveRecord::DeleteRestrictionError if u.posts.any?
irb(main):002:0> u.destroy
TRANSACTION (0.1ms) begin transaction
Post Exists? (0.1ms) SELECT 1 AS one FROM "posts" WHERE "posts"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 1]]
TRANSACTION (0.0ms) rollback transaction
Traceback (most recent call last):
1: from (irb):2
ActiveRecord::DeleteRestrictionError (Cannot delete record because of dependent posts)
:destroy => a.destroy will call a.bs.destroy_all
restrict_with_error
:restrict_with_error => causes an error to be added to the owner if there is an associated object
irb(main):002:0> u.destroy
TRANSACTION (0.1ms) begin transaction
Post Exists? (0.1ms) SELECT 1 AS one FROM "posts" WHERE "posts"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 1]]
TRANSACTION (0.1ms) rollback transaction
=> false
irb(main):003:0> u.errors
=> #<ActiveModel::Errors:0x00007fc2b209d428 @base=#<User id: 1, name: "John", email: "some@email.com", created_at: "2021-04-10 13:17:09.423794000 +0000", updated_at: "2021-04-10 13:17:09.423794000 +
0000">, @errors=[#<ActiveModel::Error attribute=base, type=restrict_dependent_destroy.has_many, options={:record=>"posts"}>]>
Top comments (0)