У меня есть модель утверждения отпуска, в которой has_many :entries есть ли способ, чтобы, если я уничтожу одну из этих записей, остальные были уничтожены? Я также хочу отправить одно электронное письмо, если они есть, но не по одному для каждой записи. Есть ли способ наблюдать за изменениями в коллекции в целом?
обратные вызовы для активных ассоциаций записей
Ответы (5)
Обратный вызов, вероятно, не является хорошим выбором, потому что:
class Entry < ActiveRecord::Base
def after_destroy
Entry.where(:vacation_id => self.vacation_id).each {|entry| entry.destroy}
end
end
приведет к плохой рекурсии.
Возможно, вы должны сделать это в контроллере:
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
Вы можете использовать обратный вызов before_destroy
.
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
Обязательно протестируйте этот код, прежде чем использовать его для чего-то важного, но он должен дать вам некоторое направление для начала работы.
mark_for_destruction
полезен только с :autosave, так что я попробую, когда увижу, что происходит с :dependent =› destroy
- person loosecannon; 24.06.2011
:autosave
. Однако будьте осторожны, когда ставите :dependent => :destroy
. Вы хотите, чтобы сам VacationRequest
уничтожался всякий раз, когда уничтожается любая из его записей?
- person Luke; 24.06.2011
Я думаю, что это должно работать:
class Entry < ActiveRecord::Base
belongs_to :vacation_request, :dependent => :destroy
# ...
end
class VacationApproval < ActiveRecord::Base
has_many :entries, :dependent => :destroy
# ...
end
Что должно произойти, так это то, что при уничтожении Записи связанный с ней VacationApproval будет уничтожен, а впоследствии все связанные с ним Записи будут уничтожены.
Дайте мне знать, если это работает для вас.
Итак, что я в итоге сделал, это
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."
а потом
@entries.each {|entry| entry.destroy if entry.invalid? }
в индексном действии моего контроллера. и
`raise "Entries are not valid, please check them and try again ( Did you cancel your vacation? )" if @entries.any? &:invalid?`
в действии отправки
Проблема с одновременным удалением других заключается в том, что мой пользовательский интерфейс делает 10 вызовов Ajax для выбора 10 строк и удаляет их все в первый раз, когда я получаю 9 необработанных ответов 404, что было нежелательно.
Поскольку меня это не волнует, они остаются там, пока Заявка не может быть отправлена, все в порядке.
Это был самый простой/безопасный/дружественный к рекурсии способ для меня, но, вероятно, не лучший способ. Спасибо за вашу помощь!
Кому интересно/ищу информацию
В итоге я решил это позже, настроив модель APProval для отпуска следующим образом:
class VacationApproval < ActiveRecord::Base
has_many :entries , :conditions => {:job_id => Job.VACATION.id }, :dependent => :delete_all
end
и моя модель входа, как это
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
Использование :delete_all не обрабатывает обратные вызовы, а просто удаляет их.