Определите, какие идентификаторы были удалены из массива в обратном вызове Rails after_save?
Я пытаюсь выяснить, как я могу сказать, что изменилось в массиве в обратном вызове после сохранения. Вот пример кода, который я использую:
class User < ActiveRecord::Base
has_many :user_maps, :dependent => :destroy
has_many :subusers, :through => :user_maps, :dependent => :destroy
has_many :inverse_user_maps, :class_name => "UserMap", :foreign_key => "subuser_id"
has_one :parent, :through => :inverse_user_maps, :source => :user
after_save :remove_subusers
def remove_subusers
if self.subuser_ids_were != self.subuser_ids
leftover = self.subuser_ids_were - self.subuser_ids
leftover.each do |subuser|
subuser.destroy
end
end
end
end
class UserMap < ActiveRecord::Base
belongs_to :user
belongs_to :subuser, :class_name => "User"
end
Я удаляю subusers с обратным вызовом after_save, потому что я не мог заставить зависимую функцию уничтожения работать через user_maps. У кого-нибудь есть идеи, как это сделать?
Спасибо!
2 ответа
Вы можете использовать средства доступа к Dirty-модулю http://ar.rubyonrails.org/classes/ActiveRecord/Dirty.html как указано в разделе "Определить, какие атрибуты были изменены в обратном вызове Rails after_save?"
В вашем случае обработчик у вас есть для after_save
будет иметь доступ к subusers_change
который представляет собой массив из двух элементов, первый из которых является предыдущим значением, а второй - новым.
Хотя это не совсем ответ на ваш вопрос, я думаю, что вы, возможно, сможете получить: зависящий =>: уничтожить работу, если вы попробуете следующее...
class User < ActiveRecord::Base
has_many :user_maps, :dependent => :destroy
has_many :subusers, :through => :user_maps # removing the :dependent => :destroy option
end
class UserMap < ActiveRecord::Base
belongs_to :user
belongs_to :subuser, :class_name => "User", :dependent => :destroy # add it here
end
Перемещая опцию: зависимый =>: уничтожить в ассоциацию own_to в модели UserMap, вы устанавливаете каскадное удаление с помощью метода UserMap#destroy. Другими словами, вызов User # destroy будет вызывать UserMap#destroy для каждой записи UserMap, которая, в свою очередь, будет вызывать sub_user.destroy для своей записи sub_user.
РЕДАКТИРОВАТЬ
Поскольку вышеприведенное решение не сработало, моим следующим предложением будет добавление обратного вызова в ассоциацию user_maps, однако это сопровождается предупреждением, которое я добавлю после
class User < ActiveRecord::Base
has_many :user_maps, :dependent => :destroy, :before_remove => :remove_associated_subuser
def remove_associated_subuser(user_map)
user_map.subuser.destroy
end
end
ПРЕДУПРЕЖДЕНИЯ
1) Использование обратного вызова before_remove будет означать, что функция user_map.destroy не будет вызываться в случае ошибки обратного вызова
2) Вам придется уничтожить вашу запись UserMap, используя метод класса User, например...
# this will fire the callback
u = User.first
u.user_maps.destroy(u.user_maps.first)
# this WONT fire the callback
UserMap.first.destroy
Учитывая все обстоятельства, это заставит меня нервничать. Сначала я бы попытался изменить ваш код, чтобы сделать ассоциации немного менее связанными с одними и теми же таблицами, так что опция: зависимый =>:destroy может работать, и если вы не можете сделать это, добавьте ограничение каскадного удаления в базу данных. По крайней мере, тогда ваши ассоциации всегда будут удалены, независимо от того, где и как вы их уничтожите в своем приложении rails.