after_destroy not called for linked table - ruby-on-rails

I have these models
class User < ActiveRecord::Base
has_many :user_functions, :dependent => :destroy
has_many :functions, :through => :user_functions
accepts_nested_attributes_for :functions, allow_destroy: true
Model of the linked table:
class UserFunction < ActiveRecord::Base
belongs_to :user, inverse_of: :user_functions
belongs_to :function, inverse_of: :user_functions
after_destroy :unplan_items
after_create :plan_items
and of course the model of function but this is like user...
Now when I do the following in my tests:
#user.functions = [#functions]
#user.save
expect(#user.planned_items.count).to eq(1)
#user.functions = []
#user.save
I notice the callback after_destroy isn't called. Why is this and how can I avoid this. There are certain steps that need to be done every time a UserFunction is destroyed...
I believe this has to do with: https://github.com/rails/rails/issues/7618 (I'm using rails 4.2.5 though). The after_create is working perfect though...

Currently rails uses :delete_all as default strategy of has_many_through. It only calls :destroy_all when we explicitly specify dependent: :destroy on the association.
The docs mention advice to use has_many :through if you need callbacks:
See the suggestion here: http://guides.rubyonrails.org/association_basics.html
You should use has_many :through if you need validations, callbacks,
or extra attributes on the join model.
So there currently is an inconsistency between after_create which does do the callback and after_destroy.
This is mentioned in these two issues posted on GitHub:
https://github.com/rails/rails/issues/7618
https://github.com/rails/rails/issues/27099
The fix for now is to explicitly put :dependent => :destroy on the :through part. This will make sure the callback are used.
class User < ActiveRecord::Base
has_many :user_functions
has_many :functions, :through => :user_functions, :dependent => :destroy
accepts_nested_attributes_for :functions, allow_destroy: true

For anyone reading this 2021+
Change This
has_many :object_tags, :as => :taggable, :dependent => :destroy
has_many :tags, :through => :object_tags
To This
has_many :object_tags
has_many :tags, :through => :object_tags, :dependent => :destroy

Related

Destroy an object does not destroy associated objects using rails console

I have the following Model
class Will < ApplicationRecord
belongs_to :user
belongs_to :product
has_one :willFamilyDetail, :dependent => :destroy
has_one :childCompensate, :dependent => :destroy
has_one :wifeCompensate, :dependent => :destroy
has_one :willDebt, :dependent => :destroy
has_one :willLegalHeirBequest, :dependent => :destroy
has_one :willGrandchildrenBequest, :dependent => :destroy
has_one :willBequestOther, :dependent => :destroy
end
and all other models have belongs_to.
When I use Rails console to delete the Will object, other objects still appear in the database, they must get destroyed right?
What am I doing wrong?
ActiveRecord association symbols must be snake case, not camel case, following Ruby convention. Converting each association name from camel case to snake case (:willFamilyDetail to :will_family_detail, etc.) solves the issue.

How to call automatically method in object that needs access to unsaved associations in Rails

I have a class called Treatment with these associations:
class Treatment < ActiveRecord::Base
has_many :threat_treatments, :dependent => :destroy
has_many :threats, :through => :threat_treatments
has_many :subcategory_treatments, :dependent => :destroy
has_many :subcategories, :through => :subcategory_treatments
has_many :treatments_risks, :dependent => :destroy
has_many :risks, :through => :treatments_risks
has_many :risks_from_threats, :through => :threats, :source => :risks
has_many :risks_from_subcategories, :through => :subcategories, :source => :risks
def associate_with_existing_risks
self.risks = self.risks_from_threats & self.risks_from_subcategories
end
end
I need to execute the method associate_with_existing_risks() automatically when a treatment is created. If I use before_save callback, the two associations are still unsaved and unaccessible. If I use after_save, cause I need to save again the treatment, I will create an infinite loop.
I cannot use inverse_of because the associations are through associations.
How and when can I execute the method associate_with_existing_risks to update the risks association when a treatment is created?

Trying to design a controller to display courses (Rails)

Below are the models that are relevant to my problem. I am attempting to design a way to display CourseEnrollments along with their steps to a given patient. Here is what I have come up with so far.
INDEX ACTION - /course_enrollments/ --> Display courses user is enrolled in as well as the most recent course overview. This can redirect to most recent course.
SHOW ACTION - /course_enrollments/:id --> Display courses user is enrolled in as well as the most recent course overview
The part I am struggling to figure out is how to display an individual step for a course. Should this be done in the course_steps controller (which is nested inside the courses resource)?
class Course < ActiveRecord::Base
belongs_to :course_category
belongs_to :client
belongs_to :user_created, :foreign_key => :user_created_by, :class_name => "User"
belongs_to :user_updated, :foreign_key => :user_last_updated_by, :class_name => "User"
has_many :course_steps, :dependent => :destroy
has_many :steps, :through => :course_steps
has_many :course_requests, :dependent => :destroy
has_many :course_enrollments, :dependent => :destroy
has_many :patients, :through =>:course_enrollments
end
class CourseStep < ActiveRecord::Base
belongs_to :step
belongs_to :course
validates_uniqueness_of :step_id, :scope => :course_id
end
class Step < ActiveRecord::Base
belongs_to :step_type
belongs_to :client
has_one :step_quiz, :dependent => :destroy
has_one :step_survey, :dependent => :destroy
has_one :step_text, :dependent => :destroy
has_one :step_download, :dependent => :destroy
has_one :step_video, :dependent => :destroy
has_one :step_presentation, :dependent => :destroy
has_many :course_steps, :dependent => :destroy
has_many :courses, :through => :course_steps
end
class CourseEnrollment < ActiveRecord::Base
belongs_to :patient
belongs_to :course
end
class Patient < ActiveRecord::Base
belongs_to :user, :dependent => :destroy
has_many :enrollments, :dependent => :destroy
has_many :clients, :through => :enrollments
has_many :course_requests, :dependent => :destroy
has_many :course_enrollments, :dependent => :destroy
has_many :courses, :through => :course_enrollments
end
The usual approach is to nest these and have a compound sort of path, but how you route these things is often dependent on the level of context involved. For instance, is the display of a course driven by a user to the degree that the path should have the user in it, or is it a case of simply personalizing the course page?
Typically you see things like this:
resources :courses do |course|
course.resources :enrollments
course.resources :steps
end
There's usually a correlation between your has_many relationships and declaring an equivalent resources but not always.
Have a look at the generated routes using rake routes to see what the parameters will be called when passed to your controller, as well as what the expected controller name will be. You can customize the name of the controller by passing in a :controller option to the route.
Typically the last record in the path is passed in as :id whereas the prior ones are named, such as :course_id. This is a somewhat annoying inconsistency, so do be careful to check you're loading using the correct parameters.
If you need to display an individual step for a course, you definitely need to use the course_steps controller, logic being, each CourseStep object is a combo of one-course and one-step.

Is this the correct way to use way :dependent => :destroy in my RoR app?

This is how my RoR app is setup
note.rb
belongs_to :user
has_many :note_categories
has_many :categories, :through => :note_categories
category.rb
has_many :note_categories
has_many :notes, :through => :note_categories
I want to make it so that when a user deletes a note, the corresponding entry in the note_categories table is deleted as well. Do I use :dependent => :destroy to do that?
Also, if I wanted to make it so that if a user deletes a note, and that means that there are no more notes with the category it had, the category itself was deleted, how would I do that? Thanks for reading.
I want to make it so that when a user
deletes a note, the corresponding
entry in the note_categories table is
deleted as well. Do I use :dependent
=> :destroy to do that?
Yes, that's correct.
Also, if I wanted to make it so that
if a user deletes a note, and that
means that there are no more notes
with the category it had, the category
itself was deleted, how would I do
that?
You use an after_destroy callback.
class Note < ActiveRecord::Base
belongs_to :user
has_many :note_categories, :dependent => :destroy
has_many :categories, :through => :note_categories
end
class Category < ActiveRecord::Base
has_many :note_categories, :dependent => :destroy
has_many :notes, :through => :note_categories
end
class NoteCategory < ActiveRecord::Base
belongs_to :note
belongs_to :category
after_destroy { category.destroy if category.notes.empty? }
end

rails, accepts_nested and has_many :through is creating duplicate entries

I have a store model that has many products with a has_many :through relationship.
I have this working with accepts_nested_attributes, but the result is that rails is making duplicate associates.
I don't have anything special going on it is a very simple app.
Any ideas on why duplicates associates are getting created?
look at answer : how to avoid duplicates in a has_many :through relationship? here :
add :uniq => true to the has_many :through
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers, :uniq => true
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :blogs, :through => :blogs_readers, :uniq => true
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
This is a confirmed bug in Rails, with a fix set to be included in 2.3.6.
https://rails.lighthouseapp.com/projects/8994/tickets/3575-multiple-join-records-when-using-nested_attributes-in-habtm

Resources