user model
class User < ApplicationRecord
has_many :posts
accepts_nested_attributes_for :posts, allow_destroy: true
end
post model
class Post < ApplicationRecord
belongs_to :user
accepts_nested_attributes_for :user, allow_destroy: true
end
user controller
class Api::UsersController < ApiController
def destroy
User.destroy(params[:id])
end
end
I thought if I destroy the user using destroy, all the posts related to user will be deleted automatically.
But still nothing is deleted.
What I am doing wrong here?
You can use dependent: :delete_all
has_many :posts, :dependent => :delete_all
Related
If I delete child record so parent record does not get deleted automatically.
class User < ActiveRecord::Base
has_one :agency, dependent: :destroy
accepts_nested_attributes_for :agency
end
class Agency < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end
if #agency.present?
#agency.user.destroy
flash[:notice] = 'Agency Deleted'
end
Destroy child record so parent record automatically destroy.
I think, your models could be re-written like this to achieve expected output.
class User < ActiveRecord::Base
has_one :agency # Change
accepts_nested_attributes_for :agency
end
class Agency < ActiveRecord::Base
belongs_to :user, dependent: :destroy # Change
accepts_nested_attributes_for :user
end
if #agency.present?
#agency.destroy # Change
flash[:notice] = 'Agency Deleted'
end
Let's think logically now.
What have you changed is, you made User dependent on Agency and now it's rails doable to form a parent-child relationship to get accepted output. So when you destroy an #agency, it will also delete the dependent user record.
You should use the following code to delete a user and its associated agency without making any change to your model.
class User < ActiveRecord::Base
has_one :agency, dependent: :destroy
accepts_nested_attributes_for :agency
end
class Agency < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end
if #agency.present?
user = #agency.user #Change
user.destroy # This will destroy both user and associated agency.
flash[:notice] = 'Agency and User Deleted'
end
A complete official guide on dependent: :destroy can be find here.
I have setup a polymorphic liking in my my app where a user can like other models e.g book, chapter, article... Now I tried to take it a little further by allowing a user like another user but I'm running to this error:
Validation failed: User must exist
pointing to
likes.where(item: item).create!
This is my initial setup for liking other models excluding the user model
like.rb
belongs_to :user
belongs_to :item, polymorphic: true
user.rb
has_many :likes, dependent: :destroy
def toggle_like!(item)
if like = likes.where(item: item).first
like.destroy
else
likes.where(item: item).create!
end
end
def likes?(item)
likes.where(item: item).exists?
end
likes_controller.rb
class LikesController < ApplicationController
before_action :authenticate_user!
def toggle
if params[:book_id]
item = Book.friendly.find(params[:book_id])
elsif params[:user_id]
item = User.find_by(username: params[:username])
end
current_user.toggle_like!(item)
redirect_back(fallback_location: root_path)
end
end
book.rb
has_many :likes, as: :item, dependent: :destroy
For a user to like another user, i adjusted the user.rb from
has_many :likes
to
has_many :likes, as: :item, dependent: :destroy
This is when I get the error
Validation failed: User must exist
pointing to
likes.where(item: item).create!
in the user.rb
Keep has_many :likes, dependent: :destroy and also add has_many :received_likes, as: :item, class_name: "Like", dependent: :destroy. I think that will fix it. Because when you put User has_many: :likes, as: :item, and removed User has_many: :likes, this means that the association Like belongs_to :user was one-sided.
In Rails when I have made one Model as the foreign key in another model then I can delete that model while speciying its relation like:
class User < ApplicationRecord
has_many :garments, dependent: :destroy
end
But if I have one model which is created in another namespace like superadmin them how to write the dependent destroy relation in that case
for example I am using :
class User < ApplicationRecord
has_one superadmin::company , dependent: :destroy
end
which is incorrect.
The model company is present in namespace superadmin, please tell if their is a correct a way possible. Thanks in advance
It's incorrect, Way of reference to model and namespace with class name is incorrect:
incorrrect:
class User < ApplicationRecord
has_one superadmin::company , dependent: :destroy
end
corrrect:
class User < ApplicationRecord
has_one :company, :class_name => "Superadmin::Company", :dependent => :destroy
end
class User < ApplicationRecord
has_one :company, :class_name => "Superadmin::Company", :dependent => :destroy
#has_many :companies, :class_name => "Superadmin::Company", :dependent => :destroy
end
I have 2 models
class Deal < ActiveRecord::Base
has_many :couponizations, dependent: :destroy
has_many :coupon_codes, through: :couponizations, source: :coupon_code, dependent: :destroy
accepts_nested_attributes_for :coupon_codes, allow_destroy: true
end
and
class CouponCode < ActiveRecord::Base
has_one :couponization, dependent: :destroy
has_one :deal, through: :couponization, source: :deal
which are linked by many-to-many relationship
class Couponization < ActiveRecord::Base
belongs_to :coupon_code
belongs_to :deal
end
Despite I specified dependent: :destroy option, when I delete deal, coupon codes are not being deleted. However couponizations are deleted successfully. Is there any way to delete associated nested records on object destroy?
The options dependent: :destroy is ignored when using with the :through (see doc). You have to do it manually, with a after_destroy callback for example.
class Deal
after_destroy :destroy_coupon_codes
private
def destroy_coupon_codes
self.coupon_codes.destroy_all
end
end
I recommend using :after_destroy callback, so if destroying some Deal instance fails for whatever reason you don't end up deleting all of its CouponCodes.
Here's an :after_destroy example that should work:
after_destroy { |record|
CouponCode.destroy(record.coupon_codes.pluck(:id))
}
Make sure to remove dependent: :destroy from has_many :couponizations in the Deals model, because all couponizations will now be destroyed by the has_one :couponization, dependent: :destroy in the CouponCode model.
How can I delete nested objects in a form? I found out that I need to add :allow_destroy in the parent model at the accepts_nested_attributes_for directive.
Further, I want to restrict the deletion. A nested object only should be deleted, if the parent object is the only one that retains the association.
Example:
class Internship < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company, allow_destroy => true
end
class Company < ActiveRecord::Base
has_many :internships
end
Explanation: A company can host many internships. Therefore, I do not want to delete the company record as long as there is at least one other internship associated with it.
You could use dependent => :destroy
class Internship < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company, allow_destroy => true
end
class Company < ActiveRecord::Base
has_many :internships, :dependent => :destroy
end
If you return false in a before_destroy filter, then the destroy action will be blocked. So we can check to see if there are any internships associated to the company, and block it if so. This is done in the company model.
class Company < ActiveRecord::Base
has_many :internships
before_destroy :ensure_no_internships
private
def ensure_no_internships
return false if self.internships.count > 0
end
end