Understanding Devise roles

After Devise was released, there were some misunderstandings about Devise roles and how to use it. And the best way to understand it is explaining which problem we wanted to solve when we designing Devise.

In most applications developed at Plataforma, we usually have two actors: one which represents the client who hired us and another which is the end-user, the audience of the developed app.

Before Devise, we used Authlogic or Clearance as authentication solutions. Authlogic does not say anything about controllers, so we usually had two models (Admin and User) and some controllers to handle sign in, password reset and so forth for each model, which required expressive effort to handle and maintain.

On the other hand, we had Clearance. Clearance deals completely with the User model, but we needed to work on the Admin model almost from scratch.

With Devise, we can have a full stack solution for both User and Admin. But that only works if User and Admin does not need to share a lot of responsibilities.

For instance, if you are working on a blogging system with different roles as “editor”, “author” and “contributor”, but they all share a lot of activities in common, as writing a post, handling such roles with Devise can add a great of complexity to your code, mainly because you will need to use Single Table Inheritance (STI) and/or polymorphic relationships very frequently.

To handle such cases, you can use any of the authorization libraries out there for Rails (remember that Devise is mainly an authentication tool).

Scoped authentication

On the same line, there were some requests to provide authentication by username, instead of e-mail, or providing a subdomain as scope for the authentication. You can now do that using Devise 0.5.1 or higher by just setting the authentication keys in your model:

class User  [ :username, :subdomain ]
end

Now you user needs an username and subdomain to authenticate and their respective value should be sent as parameters when signing in. Such values are converted to conditions when retrieving the user from the database for authentication. For example, the following path with query string:

/users/sign_in?user[username]=josevalim&user[subdomain]=plataformatec

Is converted to the following query with ActiveRecord:

User.first(:conditions => { :username => "josevalim", :subdomain => "plataformatec" })

And only after retrieving the user we check for password validity. However, keep in mind that those conditions are used only when signing in. If an user is already authenticated, it will be retrieved from session, where such conditions are not used. In other words, you still need a filter in your controllers to verify that the user accessing a given subdomain, is really allowed to access that subdomain.

Such configuration should handle most of the cases, but if you still need more customization, you can overwrite three class methods exposed for exactly this purpose: User.authenticate, User.serialize_into_session and User.serialize_from_session.

Enjoy!

2 responses to “Understanding Devise roles”

  1. Hi! Very nice update! I was actually one of those people that asked if there was a possibility for using another attribute (other than the email attribute) to do authentication with. For my next project (which I’ll be starting on soon) I was still undecided whether to go with Authlogic or Devise. Not because I’d rather use a “username” over “email”, because the next project will probably use the email attribute to authenticate, but because I don’t want to continuously change authentication gems because depending on whether I need another attribute or not. But this update made me decide to go with Devise with new introduction of the scoped authentication feature. Next to just being able to say: “Use the Username Attribute”, that you can say: “Use the Username Attribute that belongs to ‘this’ subdomain/account/website” or whatever. This is actually the perfect solution for one of my current projects, so you at the same time inspired me with this blog post!

    Thanks a lot!

  2. Hi! Very nice update! I was actually one of those people that asked if there was a possibility for using another attribute (other than the email attribute) to do authentication with. For my next project (which I’ll be starting on soon) I was still undecided whether to go with Authlogic or Devise. Not because I’d rather use a “username” over “email”, because the next project will probably use the email attribute to authenticate, but because I don’t want to continuously change authentication gems because depending on whether I need another attribute or not. But this update made me decide to go with Devise with new introduction of the scoped authentication feature. Next to just being able to say: “Use the Username Attribute”, that you can say: “Use the Username Attribute that belongs to ‘this’ subdomain/account/website” or whatever. This is actually the perfect solution for one of my current projects, so you at the same time inspired me with this blog post!

    Thanks a lot!