Определите, какие идентификаторы были удалены из массива в обратном вызове Rails after_save? - PullRequest
0 голосов
/ 02 октября 2011

Я пытаюсь выяснить, как я могу узнать, что изменилось в массиве в обратном вызове после сохранения.Вот пример кода, который я использую:

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

Я удаляю подпользователей с помощью обратного вызова after_save, потому что я не смог заставить зависимую функцию уничтожения работать через user_maps.У кого-нибудь есть идеи, как это сделать?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 02 октября 2011

Вы можете использовать аксессоры Dirty модуля http://ar.rubyonrails.org/classes/ActiveRecord/Dirty.html, как предложено в Определить, какие атрибуты были изменены в обратном вызове Rails after_save?

В вашем случае обработчик, который вы используете для after_save будет иметь доступ к subusers_change, который представляет собой массив из двух элементов, первый из которых является предыдущим значением, а второй - новым.

0 голосов
/ 02 октября 2011

хотя это не совсем ответ на ваш вопрос, я думаю, что вы, возможно, сможете получить: зависимый =>: уничтожить работающий, если попытаетесь выполнить следующее ...

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

Перемещая: зависимый =>Опция: destroy для ассоциации own_to в модели UserMap, которую вы установили каскадным удалением с помощью метода UserMap # destroy.Другими словами, вызов User # destroy вызовет UserMap # destroy для каждой записи UserMap, которая, в свою очередь, вызовет sub_user.destroy для своей записи sub_user.

EDIT

Поскольку вышеприведенное решение не сработало, моим следующим предложением было бы добавить обратный вызов в ассоциацию 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

WARNINGS

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

Учитывая все обстоятельства, это заставит меня нервничать.Сначала я бы попытался изменить ваш код, чтобы сделать ассоциации немного менее связанными с одними и теми же таблицами, так что опция: variable =>: destroy может работать, и если вы не можете этого сделать, добавьте ограничение каскадного удаления в базу данных., по крайней мере, тогда ваши ассоциации всегда будут удалены, независимо от того, где и как вы их уничтожите в своем приложении rails.

...