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!
精彩评论