Rails: How to use dependent: :destroy in rails? - ruby-on-rails

I have 2 models as describes below.
class EmpGroup < ActiveRecord::Base
belongs_to :user
has_many :emp_group_members, dependent: :destroy
end
and
class EmpGroupMember < ActiveRecord::Base
belongs_to :emp_group
belongs_to :user
end
now the problem is whenever I tried to destroy a group then I received a error as below.
PG::ForeignKeyViolation: ERROR: update or delete on table "emp_groups" violates foreign key constraint "fk_rails_bd68440021" on table "emp_group_members"
DETAIL: Key (id)=(1) is still referenced from table "emp_group_members".
What I'm missing?

Add cascading delete to your EmpGroup model:
class EmpGroup < ActiveRecord::Base
has_many :emp_group_members, dependent: :delete_all
end
Or
Are you calling delete method? you should call destroy instead.
Use .destroy

:dependent is one of the options available in belongs_to association
If you set the :dependent option to:
:destroy, when the object is destroyed, destroy will be called on its associated objects.
:delete, when the object is destroyed, all its associated objects will be deleted directly from the database without calling their destroy method.
Additionally, objects will be destroyed if they're associated with dependent: :destroy, and deleted if they're associated with dependent: :delete_all.
in has_many associations:
: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)
you can try
emp_member_1= #emp_group.emp_group_members.first
##delete associated record
#emp_group.emp_group_members.delete(emp_member_1)

New syntax:
class EmpGroup < ActiveRecord::Base
has_many :emp_group_members, dependent: :destroy
end

When you delete a group, are you using delete or destroy. - I've had this error before, and it was because I had a typo and was using .delete instead of .destroy

Insert relation like this
has_many :children, :dependent => :destroy
To learn more about destroy and delete, go to this link
https://medium.com/#wkhearn/delete-vs-destroy-does-it-even-matter-8cb4db6aa660

Related

Remove the reference id from the record when the owner is deleted

Let's say I have a Post model:
class Post < ActiveRecord::Base
belongs_to :category
end
and a Category model:
class Category < ActiveRecord::Base
has_many: :posts
end
I can use dependent: :destroy to have all the posts deleted when a specific category is deleted, but I don't want to remove the posts, I just want to remove the association to that specific category by just setting the category_id column of those posts to nil.
Is there a "Rails Way" of doing this out of the box, or do I need to use some callbacks?
use dependent: :nullify
Per the Rails guide:
:nullify causes the foreign key to be set to NULL. Callbacks are not
executed.
So you'd have:
class Category < ActiveRecord::Base
has_many: :posts,
dependent: :nullify
end

Avoid duplicate entry with has_many through rails

I have been using this nested attributes with has_many :through
class Check < ActiveRecord::Base
has_many :checks_tags, dependent: :destroy
has_many :tags, through: :checks_tags
attr_accessible :tags_attributes, :checks_tags_attributes
accepts_nested_attributes_for :tags, :checks_tags
end
class Tag < ActiveRecord::Base
has_many :checks_tags, dependent: :destroy
has_many :checks, through: :checks_tags
end
class CheckTag < ActiveRecord::Base
belongs_to :check
belongs_to :tag
end
so here the issue is when i create with this hash
"tags_attributes"=>[{"id"=>"", "name"=>"test12", "company_id"=>"1"}, {"id"=>"", "name"=>"test12", "company_id"=>"1"}]
actually here have two tags with same name, so its creating Tag twice and after putting twice on CheckTag, so is there any way to avoid this creation as twice in Tag?
If you want it forbidden in the database, you could create a unique index on the combination of the two columns on the check_tag table. If you want to handle it in rails, you can do it with a before_save callback on the Check model (if that's the only way you create these), but that may make you vulnerable to a race condition.
See this answer:
Index on multiple columns in RoR

Has_many through association with dependant: destroy not destroying

I have this model
class XmlImport < ActiveRecord::Base
belongs_to :video
belongs_to :user
has_many :events, through: :event_import_records, dependent: :destroy
has_many :event_import_records, dependent: :destroy
has_attached_file :xml
validates_attachment_content_type :xml, :content_type => ["text/xml"]
end
The :event_import_records entries are being destroyed. But the :events are not.
Is the dependent:destroy on the has_many through association valid?
Is there another way of writing it? If that is not correct
How can I destroy all the events associated to the XmlImport through the event_import_records?
You can find at the Rails API that: "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." I understand that it delete the joins records but not the associated by through.
If I were you, I try:
class EventImportRecord < ActiveRecord::Base
has_many :events, dependent: :destroy
end
If not work I swap the order of the has_many relations on the XmlImport model, because of "Note that :dependent is implemented using Rails' callback system, which works by processing callbacks in order. Therefore, other callbacks declared either before or after the :dependent option can affect what it does." Also find at the same page of the Rails API.

Proper way to delete has_many :through join records?

class Post < ActiveRecord::Base
has_many :posts_tags
has_many :tags, through: :posts_tags
end
class PostsTag < ActiveRecord::Base
belongs_to :post
belongs_to :tag
end
class Tag < ActiveRecord::Base
has_many :posts_tags
has_many :posts, through: :posts_tags
end
When Post gets destroyed I want all of its associations to Tag deleted as well. I do NOT want validations on PostsTag model to run. I just want to deleted.
I've found that adding a dependent on the relationship to posts tags from the Post model works as I want: has_many :posts_tags, dependent: :delete_all.
However, the documentation on the subject seems to suggest that I should do this instead: has_many :tags, through: :posts_tags, dependent: :delete_all. When I do this, the Tag object gets destroyed and the join object remains.
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
For has_many, destroy will always call the destroy method of the record(s) being removed so that callbacks are run. However delete 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 :nullify (set the foreign keys to nil), except for has_many :through, where the default strategy is delete_all (delete the join records, without running their callbacks).
How can I have the default strategy actually used? If I leave :dependent off completely, no records are removed at all. And I cannot just indicate :dependent on a has_many relationship. Rails comes back and says "The :dependent option expects either :destroy, :delete_all, :nullify or :restrict ({})".
If I don't specify :dependent on either of the relationships, it does NOT nullify the post_id on the PostsTag object as it seems to suggest
Perhaps I am reading this wrong and the approach that I found works is the correct way?
Your original idea of:
has_many :posts_tags, dependent: :delete_all
is exactly what you want. You do not want to declare this on the has-many-though association :tags, as that will destroy all associated Tags. What you want to delete is the association itself - which is what the PostTag join model represents.
So why do the docs say what they do? You are misunderstanding the scenario that the documentation is describing:
Post.find(1).destroy
Post.find(1).tags.delete
The first call (your scenario) will simply destroy the Post. That is, unless you specify a :dependent strategy, as I suggest you do. The second call is what the documentation is describing. Calling .tags.delete will not (by default) actually destroy the tags (since they are joined by has-many-through), but the associated join model that joins these tags.

ActiveRecord callbacks on associations that are replaced by a new collection

Callbacks on objects which are updated during removal from a relationship collection don't seem to be executing for me.
I have a model EntityLocation which serves as a polymorphic relationship between Entities (Users/Places/Things) and Locations (Zips, Addresses, Neighborhoods).
class EntityLocation < ActiveRecord::Base
belongs_to :entity, :polymorphic => true
belongs_to :location, :polymorphic => true
def after_save
if entity_id.nil? || location_id.nil?
# Delete me since I'm no longer associated to an entity or a location
destroy
end
end
end
For this example, lets assume that I have a "Thing" with a collection of "Locations", referenced by my_thing.locations. This returns a collection of Zip, Address, etc.
If I write the code
my_thing.locations = [my_thing.locations.create(:location => Zip.find(3455))]
then as expected a new EntityLocation is created and can be accurately referenced from my_thing.locations. However the problem is that the records which were previously contained within this collection are now orphaned in the database with a nil entity_id attribute. I'm trying to delete these objects in the after_save callback, however it's never getting executed on the old object.
I've also tried using an after_update, and after_remove and neither gets called on the old record. The newly created record after_save callback does get called as expected, but that doesn't help me.
Does Rails update the previously referenced object without executing the callback chain through active record? All ideas appreciated. Thank you.
Why does this need to be polymorphic? It seems that you could simply use has_many :through to model the many-to-many relationship.
Secondly, why not simply delete the join table row through the association with :dependent => :destroy? Then you don't need a custom callback
class Entity < ActiveRecord::Base
has_many :entity_locations, :dependent => :destroy
has_many :locations, :through => :entity_locations
end
class EntityLocation < ActiveRecord::Base
belongs_to :entity
belongs_to :location
end
class Location < ActiveRecord::Base
has_many :entity_locations, :dependent => :destroy
has_many :entities, :through => :entity_locations
end
Now deleting from either side deletes the join table row as well.

Resources