Rails: dependent: :destroy - How does this work? - ruby-on-rails

In an example where there is an association of Owner that is as fellows:
class Owner < ActiveRecord::Base
has_many :buildings, dependent: :destroy
end
The other side of relationship:
class Building < ActiveRecord::Base
belongs_to :owner
end
If I were to delete an Owner, would it destroy the associated Building(s) as well? How can I specify a dependent relationship so that the owner and primary key is no longer associated with any Building(s) if I delete an Owner?

You probably want :nullify. See the Rails docs for has_many.
:dependent controls what happens to the associated objects when their owner is destroyed. Note that these are implemented as callbacks, and Rails executes callbacks in order. Therefore, other similar callbacks may affect the :dependent behavior, and the :dependent behavior may affect other callbacks.
:destroy causes all the associated objects to also be destroyed.
:delete_all causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
:nullify causes the foreign keys to be set to NULL. Callbacks are not executed.
:restrict_with_exception causes an exception to be raised if there are any associated records.
:restrict_with_error causes an error to be added to the owner if there are any associated objects.
If using with the :through option, the association on the join model must be a belongs_to, and the records which get deleted are the join records, rather than the associated records.

Yes, it will delete the associated buildings as dependent :destroy specified.
If you want to keep the building record, I suggest you use a join table, so that when owner is deleted, only the record in the join table is deleted.

Related

Delete/Destroy record on join_table with has_many through

I render a set of checkboxes and I want to delete all the Privilege of a User.
When I check one of the checkboxes, a record is created.
When I uncheck one of the checkboxes, a record is deleted.
I have searched all the questions related, but unluckily none works.
Rails 5.2.3
User
has_many :user_privileges, class_name: 'UserPrivileges'
has_many :privileges, through: :user_privileges
Privilege
has_many :user_privileges, class_name: 'UserPrivileges'
has_many :users, through: :user_privileges
UserPrivileges
belongs_to :user
belongs_to :privilege
The issue kick in when I want to delete ( uncheck ) the last privilege-record of that user in the join_table.
The record is still there, and there is no way to delete/destroy that specific record.
My intuition recall to the callbacks, I have tried different ways of using dependent but the last record is still there.
Any tips are welcome.
Thanks
If you want to delete the record from the join table, you need to add dependent: :destroy to has_many :through relationship.
# privilege.rb
has_many :user_privileges, class_name: 'UserPrivileges'
has_many :users, through: :user_privileges, dependent: :destroy
See What gets deleted? in API docs:
There is a potential pitfall here: has_and_belongs_to_many and
has_many :through associations have records in join tables, as well as
the associated records. So when we call one of these deletion methods,
what exactly should be deleted?
The answer is that it is assumed that deletion on an association is
about removing the link between the owner and the associated
object(s), rather than necessarily the associated objects themselves.
So with has_and_belongs_to_many and has_many :through, the join
records will be deleted, but the associated records won't.
To run dependent: :destroy callback, you must use the destroy or destroy_all method when deleting the privilege record.
See Delete or destroy? in API docs:
For has_many, destroy and destroy_all will always call the destroy
method of the record(s) being removed so that callbacks are run.
However delete and delete_all will either do the deletion according to
the strategy specified by the :dependent option, or if no :dependent
option is given, then it will follow the default strategy. The default
strategy is to do nothing (leave the foreign keys with the parent ids
set), except for has_many :through, where the default strategy is
delete_all (delete the join records, without running their callbacks).

Rails has_many associations delete parent object but not children

The scenario is that there is two models one is Room and other one is Tickets and the relationship is Room has_many :tickets.
The requirement is that when a room is deleting tickets should not be delete. How to accomplish this because tickets table have foreign key called as room_id ?
And Suppose if I am able to do this then how I will be able to get the room information for that particular ticket ?
This is a general behaviour of Rails. I guess you're using the dependent: :destroy in your association.
What you would want to do is dependent: :nullify. This would delete your room object without deleting the associated tickets and only update the room_id to null in the tickets
class Room < ActiveRecord::Base
has_many :tickets, dependent: :nullify
end
As per your second question to access the room details after deletion, i would suggest you to use soft_delete instead of actual deleting. Here, what you'll be doing is that when the room is being deleted, instead of actully deleting it, you'll soft delete it. Hence, the tickets records will persists and you'll also be able to use the room details.
There are gems available for same. One such gem is Paranoia. You can look up various tutorials on this gem.
Hope this is helpful. Let me know if you need any other guidance.
you can do this
class Room < ActiveRecord::Base
has_many :tickets,dependent: :nullify
end
checkout this
Add dependent: :nullify to has_many association, this will change foreign_key by a null after delete parent:
has_many :tickets, dependent: :nullify
Look at rails documentation: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

When parental record is deleted, are childrecord deleted automatically by accepts_nested_attributes_for?

Here is an example on Rails 3.2 api for accepts_nested_attributes_for:
class Book < ActiveRecord::Base
has_one :author
has_many :pages
accepts_nested_attributes_for :author, :pages
end
Our question is that if a book record is deleted, are child records of author and pages deleted automatically along with the book record? Or we have to explicitly delete the child records in controller.
No, you need to set the dependent key.
has_many :pages, dependent: :destroy
As the OP points out there is another option for delete_all. The difference is that delete_all won't fire the model's before_destroy callbacks, it will just wipe them from the database.
This is beneficial because it doesn't require the Rails to load DB objects into Ruby, which is slow, but it also deletes them regardless of your defined callbacks.

Rails -- how to structure belongs_to/has_many associations?

Pretty simple question, I think: so I have a User model, a Product model, and a Comment model. I want the Users to be able to comment on specific products (like leave reviews for the products).
Is this the correct structure?
User
has_many :comments
Product
has_many :comments
Comment
belongs_to :user
belongs_to :product
Thanks.
yes it's correct if you want just comment on products, if you will comment on other model other than product, then use polymorphic association.
also don't forget to add dependent: :destroy to destroy related comments if the product is destroyed or the user is destroyed
in Product and User model add dependent: :destroy
has_many :comments, dependent: :destroy
if you want other behavior than this, there is other options, from Doc :
:dependent
Controls what happens to the associated objects when their owner is
destroyed:
:destroy causes all the associated objects to also be destroyed
:delete_all causes all the associated objects to be deleted directly from the database (so callbacks will not execute)
:nullify causes the foreign keys to be set to NULL. Callbacks are not executed.
:restrict_with_exception causes an exception to be raised if there are any associated records
:restrict_with_error causes an error to be added to the owner if there are any associated object

How do I set a belongs_to association to Nil when the associated object is destroyed

Say I have:
class Car < ActiveRecord::Base
belongs_to :brand
end
class Brand < ActiveRecord::Base
has_many :cars
end
If I destroy a Brand object, the child Cars still have their car.brand_id attributes set to the destroyed brand.id.
How can I null out the car.brand_id of the child Cars when destroying the parent Brand?
I thought the ActiveRecord relationship would handle this, and prevent orphaned objects.
I don't want to dependent: :destroy the Cars, but just want to have their car.brand_id set to nil.
I don't want to have to write an after_commit for this, I want Rails magic to handle this. Or less ideally a foreign key constraint.
What about dependent: :nullify on Brand model?
4.3.2.4 :dependent
Controls what happens to the associated objects when their owner is destroyed:
...
:nullify causes the foreign keys to be set to NULL. Callbacks are not executed.
...
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference

Resources