user routing versus admin routing strategies?

In an app where ordinary users are limited to viewing and editing their own "stuff", but someone with admin privs can view and edit anybody's stuff, what's the right strategy for routing?

At first blush, I'd think that an ordinary user (e.g. with id 565) should see something like:

... where the controller assumes @current_user has been established by authlogic or whatnot. But if you're logged in as an admin, you could get at that same user's stuff via:

and you could list and administer all the users via:

Does this sound like the right approach? If so, what are the patterns for the routes and controllers? If not, what's the accepted DRY, RESTful approach?


- ff

Check out acl9 for access control

With acl9 you control what users have access to which specific methods and assign users roles on specific objects. You could set it up in the create method of stuffs_controller so the current_user is the "owner" of that stuff and only allow owners to edit that specific object, then admin has access to all.

In that approach it's all handled in the models and controllers so routes are set up however you want.

I'm using Cancan, which works really well and is pretty cleanly implemented. Check out Ryan Bates Railscast here #192 Authorization with CanCan - RailsCasts.

The urls you have up there end in .html, which doesn't really happen all that often in rails. With routes, what you're more likely going to have is:\#\#

...where ### is the user_id (or whatever). This goes to the show action for user ###. If the user_id matches the current_user or if current_user is an admin, they get to access to that model. If not, they'll get redirected. Furthermore, if current_user is an admin, they would also get access to:

...which goes to the index action to list all of the users. Other (non- admin) users will get a nasty flash message and redirected elsewhere.

Hope I'm answering the right question. :slight_smile:



Yes, you're answering the right question. My addition of the .html suffixes (suffixen?) was a brain bubble and should be ignored.

I wonder if exposing the user id in the url is useful or prudent. I agree with most RESTful philosophy, but even if authorization code is in place to prevent the user 123 from accessing the account of user 142, exposing the db-level user ID in the URL doesn't feel right.

That's why I was asking about having two styles of routing: one where the user ID is implicit (derived from session and authentication credentials) for ordinary users, and one where the user ID is manifest in the URL (for the administrator).

But: CanCan looks like a sensible adjunct to Authlogic (even though I've already written a Role model). I'll just go with the flow and use that as it was intended.

Thanks for the pointer.

- ff

I see your point, but the user_id is just an arbitrary number used for the lookup of the correct user record. You could use anything, like user name (User.find_first_by_username(params[:username]) if you have the correct route set up. Or you could do the same thing with a randomly generated unique id that identifies the user. This all assumes you are concerned with user_id being a sequential integer. At any rate, it's tried and true.

You should be able to use your implementation of role models with CanCan. It doesn't provide roles, just authorization based on your implementation of "roles". You could, for instance, use CanCan to control access based on something as arbitrary as which UserAgent their browser is reports. Just remember to restrict access in both the View and the Controller (especially).

Good luck on your project.

Oh, and one other thought. If you are still concerned about the id in the url, in UserController#Index you could also check if the user is an admin, and if not then set params[:user_id] = current_user and then render :action => show instead of the index action. I haven't tried it in a while, but as I remember this would give non-admins a url that looks like index (e.g. but would be doing the the show action (e.g. same as\#\#\#\). You wouldn't have to play with the routing at all.

This is only a partial solution, because while it would work with the show action, the all of the other actions would still require the id in the url (i.e.\#\#\#/edit\). There might be something you could do in a routing block to hide it, or maybe something like inserting the id through rack, but I think all of those are going to be a lot of work and not much bang for the buck.