Insert child records all at once - ruby-on-rails

I have these models:
class Project < ActiveRecord::Base
has_many :task_links, -> { includes(:task).order("tasks.name") }, dependent: :destroy
has_many :tasks, through: :task_links
class TaskLink < ActiveRecord::Base
belongs_to :project
belongs_to :task
class Task < ActiveRecord::Base
has_many :task_links, dependent: :destroy
has_many :projects, through: :task_links
I want to create an after_create callback that will automatically create all task_links for all active projects and the newly created task. I can do this by looping over the active projects and creating a task_link for each, but I'm wondering if there is a nicer way to do this? Preferably with one big insert command instead of xxx.

I'm not sure why you'd need to use an after_create to do this, because I think a before_create would work quite well. With a before_create, you can save all of your task_links when your new task is saved.
class Task < ActiveRecord::Base
has_many :task_links, dependent: :destroy
has_many :projects, through: :task_links
before_create :create_task_links
def create_task_links
# I'm assuming that the where below satisfies "all active projects"
Project.where(active: true).find_each do |proj|
# build only creates objects but does not save them to your database
self.task_links.build(project: proj)
end
end
end

Related

ROR: counter cache, has_many thougth, delete with nested params

I have next models:
class Document < ActiveRecord::Base
has_many :sub_roles_documents, dependent: :destroy
has_many :sub_roles, through: :sub_roles_documents,class_name: '::SubRole'
end
class SubRole < ActiveRecord::Base
has_many :sub_roles_documents, dependent: :destroy
has_many :documents, through: :sub_roles_documents, class_name: '::Document'
end
class SubRolesDocument < ActiveRecord::Base
belongs_to :sub_role, counter_cache: :documents_count, touch: true
belongs_to :document, counter_cache: :sub_roles_count
end
And when I delete sub_roles for some documents using nested parameters counter cache sub_roles_count doesn't change, but when I add new sub_roles to documents all work fine.
If I directly remove sub_roles of documents documents.sub_roles.delete(specific_sub_role) - it's work fine too.
What is best way in my case?
I figured out a problem, all wrote in documentation:
This option can be used to configure a custom named :counter_cache. You only need this option when you customized the name of your :counter_cache on the belongs_to association.
In my case I must write next:
class Document < ActiveRecord::Base
has_many :sub_roles_documents, dependent: :destroy, counter_cache: :documents_count
has_many :sub_roles, through: :sub_roles_documents,class_name: '::SubRole'
end
Because I use the customize name for counter cache.

Including attributes from a join model in a seperate form field

I have an association setup where a Track can belong to multiple Releases through ReleaseTracks:
class Release < ApplicationRecord
has_many :release_tracks, dependent: :destroy
has_many :tracks, through: :release_tracks
end
class ReleaseTrack < ApplicationRecord
# disc, side, number
belongs_to :release
belongs_to :track
belongs_to :album
end
class Track < ApplicationRecord
has_many :release_tracks, dependent: :destroy
has_many :releases, through: :release_tracks
validates_uniqueness_of :name, scope: [:release_id, :album_id]
end
As you can see, the ReleaseTrack has three attributes disc, side, number to correctly identify the correct placement for a track on any specific release. I was wondering in the instance of creating a new track in a release form, how could I also save those three attributes?

How to trigger dependent: :destroy on a child only when grand-parent is deleted?

When I delete AdTemplate record I do not want its connected page_view_stats data to be deleted also. But when I delete a Campaign record I do want ad_templates also delete all its page_view_stats records. Maybe dependent: :destroy can accept some :if condition to achieve it?
class Campaign < ActiveRecord::Base
has_many :ad_templates, dependent: :destroy
end
class AdTemplate < ActiveRecord::Base
belongs_to :campaign
has_many :page_view_stats
end
You could use after_destroy callback in Campaign
after_destroy do
# execute some logic
end

Rails: Delete associated records on object destroy

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 to destroy has_many associations plus join table records?

In my Rails app I have these models:
class Person < ActiveRecord::Base
has_many :jobs
has_many :projects, :through => :jobs
end
class Project < ActiveRecord::Base
has_many :jobs
has_many :people, :through => :jobs
end
class Job < ActiveRecord::Base
belongs_to :person
belongs_to :project
end
When I delete a person, I want to delete all the associated jobs and projects. So I do something like:
class Person < ActiveRecord::Base
has_many :jobs, :dependent => :destroy
has_many :projects, :through => :jobs, :dependent => :destroy
end
This works great to get rid of the jobs but leaves the projects (I'm assuming because without the jobs, the person has no way to reference the project). Is there an idiomatic way to do this or do I just need to use a before_destroy callback on my jobs to remove the projects?
Thanks for any help.
This is just a guess, but try:
class Job < ActiveRecord::Base
belongs_to :person
belongs_to :project, :dependent => :destroy
end
What I think could be happening is that when you destroy a Person, Rails could be deleting your jobs records, then in the next "line" it tries to search projects, but since there are no jobs projects are not destroyed.

Resources