callbacks on active record associations
I have a vacation approval model that has_many :entries is there a way that if I destroy one of those entries to have the rest destroyed? I also want to send one email if they are, but not one for each entry. Is there a way开发者_JAVA技巧 to observe changes to the collection as a whole?
A callback probably isn't a good choice because:
class Entry < ActiveRecord::Base
def after_destroy
Entry.where(:vacation_id => self.vacation_id).each {|entry| entry.destroy}
end
end
would produce some bad recursion.
It could be that you should do it in the controller:
class EntriesController < ApplicationController
def destroy
@entry = Entry.find(params[:id])
@entries = Entry.where(:vacation_id => @entry.vacation_id).each {|entry| entry.destroy}
#send email here
...
end
end
You can use the before_destroy
callback.
class VacationRequest < ActiveRecord::Base
has_many :entries
end
class Entry < ActiveRecord::Base
belongs_to :vacation_request
before_destroy :destroy_others
def destroy_others
self.vacation_request.entries.each do |e|
e.mark_for_destruction unless e.marked_for_destruction?
end
end
end
Definitely test that code before you use it on anything important, but it should give you some direction to get started.
I think this ought to work:
class Entry < ActiveRecord::Base
belongs_to :vacation_request, :dependent => :destroy
# ...
end
class VacationApproval < ActiveRecord::Base
has_many :entries, :dependent => :destroy
# ...
end
What should happen is that when an Entry is destroyed, the associated VacationApproval will be destroyed, and subsequently all of its associated Entries will be destroyed.
Let me know if this works for you.
So What i ended up doing is
class VacationApproval < ActiveRecord::Base
has_many :entries , :conditions => {:job_id => Job.VACATION.id }, :dependent => :nullify
class Entry < ActiveRecord::Base
validates_presence_of :vacation_approval_id ,:if => lambda {|entry| entry.job_id == Job.VACATION.id} , :message => "This Vacation Has Been Canceled. Please Delete These Entries."
and then
@entries.each {|entry| entry.destroy if entry.invalid? }
in the index action of my controller. and
`raise "Entries are not valid, please check them and try again ( Did you cancel your vacation? )" if @entries.any? &:invalid?`
in the submit action
The problem with deleting the others at the same time is if my UI makes 10 Ajax calls to selete 10 rows, and it deletes all of them the first time I end up with 9 unahandled 404 responses, which was undesirable.
Since I don't care it they remain there, as long as the Entry cannot be submitted its OK.
This was the easiest / safest / recursion friendly way for me, but is probably not the best way. Thanks for all your help!
To anyone curious/ seeking info
I ended up solving this later by setting The Vacation APProval model like this
class VacationApproval < ActiveRecord::Base
has_many :entries , :conditions => {:job_id => Job.VACATION.id }, :dependent => :delete_all
end
and My Entry Model like this
class Entry < ActiveRecord::Base
after_destroy :cancel_vacation_on_destory
def cancel_vacation_on_destory
if !self.vacation_approval.nil?
self.vacation_approval.destroy
end
end
end
Using :delete_all does not process callbacks, it just deletes them
精彩评论