Posts tagged "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 < ActiveRecord::Base
 devise :all, :authentication_keys => [ :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!