开发者

Determine what ids were removed from array in Rails after_save callback?

I am trying to figure out how i can tell what has changed in an array in the after save callback. Here is an example of code i am using:

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_开发者_Go百科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

I am removing the subusers with the after_save callback because i could not get the dependent destroy feature to work through user_maps. Does anyone have any ideas on a way to do this?

Thanks!


You can use the Dirty module accessors http://ar.rubyonrails.org/classes/ActiveRecord/Dirty.html as suggested in Determine what attributes were changed in Rails after_save callback?

In your case the handler you have for after_save will have access to subusers_change which is an array of two elements, first being the previous value and second being the new value.


although not strictly the answer to your question, I think you maybe able to get :dependent => :destroy working if you try the following...

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

By moving the :dependent => :destroy option to the belongs_to association in the UserMap model you set up a cascading delete via the UserMap#destroy method. In other words, calling User#destroy will call UserMap#destroy for each UserMap record, which will in turn call sub_user.destroy for its sub_user record.

EDIT

Since the solution above didn't work, my next suggestion would be to add a callback to the user_maps association, however this comes with a warning that I will add after

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) Using a before_remove callback will mean that the user_map.destroy function won't be called if there is an error with the callback

2) You will have to destroy your UserMap record using the method on the User class for example...

# this will fire the callback
u = User.first
u.user_maps.destroy(u.user_maps.first)

# this WONT fire the callback
UserMap.first.destroy

All things considered, this would make me nervous. I would first try modifying your code to make the associations a little less coupled to the same tables, so the :dependent => :destroy option can work, and if you can't do that, add a cascade delete constraint on to the database, at least then your associations will always be removed regardless of where / how you destroy it in your rails app.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜