开发者

Having trouble with :dependent => :destroy and before_filter

开发者 https://www.devze.com 2022-12-08 11:40 出处:网络
Two models, an Account model (has_many :users) and a User model (belongs_to :account, :dependent => :destroy).

Two models, an Account model (has_many :users) and a User model (belongs_to :account, :dependent => :destroy).

My User model has the following:

def protect_master_user
  unless User.find_all_by_account_id_and_is_master(self.account_id, true).count >开发者_如何学JAVA; 1
    false
  end
end

I'm trying to protect the master users from being deleted. How can I override this if the parent (Account) is deleted? I've tried :dependent => :destroy and :delete to no avail.

EDIT: fixed code.


There are two ways to do this: has_many :users, :dependent => :delete_all, or with an additional custom callback in Accounts. The :delete_all method is simpler, but not advised, because it means that none of your other call backs will happen on the user record.

The correct solution is a custom before_destroy callback in Account, working in tandem with the callback in user.

class Account < ActiveRecord::Base
  has_many :users 

  before_destroy :destroy_users
  protected
    def destroy_users
      users.each do |user|
        u.account_id = nil
        u.destroy
      end
    end

end

class User < ActiveRecord::Base
  belongs_to :account

  before_destroy :protect_master_user

  protected
    def protect_master_user
      unless account_id.nil? ||! master || 
        User.find_all_by_account_id_and_master(self.account_id, true).count > 1
        errors.add_to_base "Cannot remove master user."
        return false
      end
    end
end

If the account.id is nil we short circuit the unless and the destroy continues. Same goes for if the user is not a master user. Why do we need to check if there's more than one master user if the object being destroyed isn't a master user either?

Again, delete could be used in place of destroy. But it skips any *_destroy callbacks you have or will ahve in the future.


I had this very same question and conundrum recently and found the best way to deal with this was to handle it in the controller as I really only care if a user is trying to delete the last Master user rather than if the system is doing it:

   class UsersController < ApplicationController
     def destroy  
       user = current_account.users.find(params[:id].to_i)
       if allow_removal_of_user?(user) && user.destroy
         redirect_to users_path, :notice => "User sucessfully deleted"
       else 
         flash[:error] = user.errors.empty? ? "Error" : user.errors.full_messages.to_sentence
         render :edit
       end 
     end 

   private
     def allow_removal_of_user?(user)
       if user == current_user
         errors.add(:user_removal, "Can't delete yourself")
         false
       elsif user.only_user? || (user.master_users_for_account.count == 1 && user.master_role?)
         errors.add(:user_removal, "Can't delete last Master user")
         false
       else
         true
       end
     end
   end

Hope this helps somebody!

0

精彩评论

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

关注公众号