Don't un-admin the last administrator

I have a User class with a field called admin which is a boolean that
determines if the user is or is not an administrator. I want to make it
impossible for the last administrator for an account to be removed from
the system.
I need to protect against this both when deleting a user and when
editing a user as you can revoke a user’s administrator privileges via a
form.

User belongs_to :account.
Account has_many :Users

I was thinking that the best way to do this would involve either
before_update and before_destroy or a validation. I think I know how to
write the before_delete as that just involves knowing which user you are
going to delete and checking if its account has more than one
administrator. I am unsure how to write before_update as that requires
not only knowing which user you are going to update but also if the
updated info would make that user no longer have admin status. I have
no idea where to start for the validation if I was to go that route for
similar reasons as the before_update.

Do any of you have any examples of code that prevents the
deletion/update of an object based on a particular field’s value?

Thank you,
Matthew M.
blog.mattmargolis.net

Matthew M. wrote:

Do any of you have any examples of code that prevents the
deletion/update of an object based on a particular field’s value?

I’ve done this, but not in the model. It’s pretty easy form the
controller.

def delete_user
user = User.find(params[:id])
if user && user.admin? && User.count(:conditions => ‘admin = 1’) == 1
flash[:notice] = “Can’t delete last admin!”
else
user.destroy
flash[:notice] = “User was deleted.”
end
redirect_to :action => ‘list’
end

Doing it from the model might a bit trickier.

I do this:

before_destroy :dont_kill_uberadmin

def dont_kill_uberadmin
raise “Cannot do this” if self.name ==
“über” end

got it from the agile book I believe


Timothy J.
Interactive Director
Found Interactive
www.foundinteractive.com
h: 540-908-4801
c: 540-810-3637

Not so, my example was in the model, but it can be done multiple ways I
guess.


Timothy J.

Timothy J. wrote:

Do any of you have any examples of code that prevents the
user.destroy
Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails
Timothy,

I am familiar with that approach but unfortunately I have multiple
accounts each with its own set of administrators so this will not work
for me.
Alex’s solution works fine for my needs for delete, I could write
something similar for update. I was hoping to get this done in the
model but controller code should be fine here.

I am definitely still open to a way to do this in the model if anyone
has any ideas.

Thank you,
Matthew M.
blog.mattmargolis.net

Curtis S. wrote:

On 6/23/06, Matthew M. [email protected] wrote:

I am definitely still open to a way to do this in the model if anyone
has any ideas.

My approach to this has always been that an admin can not remove them
self from the admin role and a user can not delete them self. With this
approach the last user can not be deleted and the last user must be the
last admin.

I’ve also always handled this in the controller. To me a model
shouldn’t have to know about anything outside it’s domain and session
information is outside the domain of the User model. (to me)

from: http://st-www.cs.uiuc.edu/users/smarch/st-docs/mvc.html

The controller interprets the mouse and keyboard inputs from the
user,
commanding the model and/or the view to change as appropriate.

In my case my controller (as described above) is deciding when it’s
appropriate to act on the users input

Michael G. wrote:

approach the last user can not be deleted and the last user must be the

commanding the model and/or the view to change as appropriate.

In my case my controller (as described above) is deciding when it’s
appropriate to act on the users input

I really like this approach! Thank you so much.

Matthew M.
blog.mattmargolis.net

On 6/23/06, Matthew M. [email protected] wrote:

I am definitely still open to a way to do this in the model if anyone
has any ideas.

You can still use the basic before_destroy hook and call a method. I
would also create a method that returns the number (or a hash or
something) of the admins on an account. This should probably be a
class method. You can then utilize that method in the before_destroy
hook to determine if there are additional admins.

Sorry, I’m thinking Java today, but psuedocode would look like:

before_destroy :dont_delete_last_admin

def dont_delete_last_admin
raise “Unable to delete final admin on account” if self.count_admins
<= 1
end

def self.count_admins
'utilize User collection to search for admins, return count
end

-Curtis

Michael G. wrote:

Curtis S. wrote:

On 6/23/06, Matthew M. [email protected] wrote:

I am definitely still open to a way to do this in the model if anyone
has any ideas.

My approach to this has always been that an admin can not remove them
self from the admin role and a user can not delete them self. With this
approach the last user can not be deleted and the last user must be the
last admin.

If I remember right, Dave T. initially chose that approach for the
AWDR tutorial, but then realised that if there are two admins, and they
are both logged on concurrently, each can delete the other.

I’ve also always handled this in the controller. To me a model
shouldn’t have to know about anything outside it’s domain and session
information is outside the domain of the User model. (to me)

I agree.

regards

Justin

If I remember right, Dave T. initially chose that approach for the
AWDR tutorial, but then realised that if there are two admins, and they
are both logged on concurrently, each can delete the other.

This isn’t an issue. Which ever admin is first will win. The second
will no longer have the necessary permissions to remove the first from
the role.

Michael G. wrote:

If I remember right, Dave T. initially chose that approach for the
AWDR tutorial, but then realised that if there are two admins, and they
are both logged on concurrently, each can delete the other.

This isn’t an issue. Which ever admin is first will win. The second
will no longer have the necessary permissions to remove the first from
the role.

If you choose to retrieve user/role information from the DB to authorise
every HTTP request, then you are right. (To be completely watertight the
reading of user/role information would have to be in the same
transaction as the authorised action.) If you cache the relevant info in
the session, then admins with concurrent sessions can delete each other.

In AWDR the admins are the only ones who log in, and authorisation is
just based on having a user ID in the session (see section 11.3 in the
first edition), so the problem arises.

You can read Dave T.'s post on the subject here:

http://article.gmane.org/gmane.comp.lang.ruby.rails/22094

regards

Justin