Rails has_many associations delete parent object but not children - ruby-on-rails

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

Related

Rails Ownership of records in many to many relations

I’m creating a Rails application and I’m having trouble regarding ownership of a record.
I have a many to many relationship and I would like to find the owner/creator of a record.
Models :
class User < ApplicationRecord
has_many :user_accounts
has_many :accounts, through :user_accounts
end
class UserAccount < ApplicationRecord
belongs_to :user
belongs_to :account
end
class Account < ApplicationRecord
has_many :user_accounts
has_many :users, through :user_accounts
end
How could I find the User that actually created the Account ?
I’ve thought about adding a owner_id field in Account with a belongs_to relationship (e.g. : belongs_to :owner, class_name: 'User' ), but I wanted to know if there was any other way or better way to achieve that ?
The solution you proposed (adding owner_id to Account) is a perfectly valid one. Here's a few more.
Add primary or owner boolean into UserAccount. Since you already have a reference to account, it might be better to use that instead of adding another relation.
Another (!dangerous!, but) with no additional columns would be to look for the earliest UserAccount according to created_at or similar. I suggest against this though, because any data migration you might do down the line might break this.

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: dependent: :destroy - How does this work?

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.

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

Adding another attribute to a many-to-many table in rails 3

I am currently using has_and_belongs_to_many to implement a many-to-many relationship. I would however want to put in a attribute in the many_to_many table.
Basically I am creating a email system. I have users and conversations. A user can have many conversations and a conversations can also have many users. However, I am trying to make it so that I can have a read/unread attribute to show which messages are read. Since conversations can have many users, it is not practicable to put the attribute in the conversations table as then it would mean that the conversation is read by all. So I think it would work best in the middle table. I am wondering though how I can access that attribute in the middle table. If the attribute is read. What code do I put in to access that and how do I update the attribute. As mention above I am using has_and_belongs_to_many
If you want to have additional attributes to your has-and-belongs-to-many association, you have to build a model class for that relation. See the detailed description in the Rails Guides about it.
After having read it for myself, this is now deprecated with the current version of Rails, so you really should switch to has_many :through. Your models could be (copied and changed from the Rails Guides, I don't know if connection is a good name for the m2n relation):
class User < ActiveRecord::Base
has_many :connections
has_many :conversations, :through => :connections
end
class Connection < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
class Conversation < ActiveRecord::Base
has_many :connections
has_many :users, :through => :connections
end
There you are able to add additional attributes to your connections table, and refer in the code to them.

Resources