Skip to content

Cantango with devise users

kristianmandrup edited this page Oct 19, 2011 · 3 revisions

CanTango has been designed from the start with an eye for easy and flexible integration with the popular popular authentication system Devise.

In Devise, you can create devise models. These models can be seen as either Users or Accounts depending on your configuration and your needs. For simple cases, Users and Accounts are seen as one and the same. In more complex scenarios it makes sense to split Users and Accounts into distinct models (see Cantango with devise accounts). In this example we will work with the Devise models as User classes that includes account functionality.

Generating a Devise User model:

$ rails generate devise User

This will create a User model with a set of devise strategies.

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :recoverable, # ...
end

Now use the tango_user macro to register this class as a user class.

class User < ActiveRecord::Base
  tango_user

  devise :database_authenticatable, :registerable, :confirmable, :recoverable, # ...

  # user logic
end

A common scenario is then to create an Admin user class like this:

class Admin < User
  tango_user

  # admin logic
end

The user class Admin can then be specialized to have its own devise strategies, validation and other logic. One example is to require a stricter password enforcement strategy and another sign-up flow.

You could also choose to make the Admin class a Devise model directly by running.

$ rails g devise Admin

In any case, you will have to make your App aware of your devise models in your routes:

  # routes.rb
  devise_for :users, :admins

This will generate distinct devise route sets for both User and Admin user types. The following devise methods will be made available in views and controllers

  • current_user - the current logged in User user (if any)
  • current_admin - the current logged in Admin user (if any)
  • user_signed_in? - is there a current logged in User user (in the session) ?
  • admin_signed_in? - is there a current logged in User user (in the session) ?

The CanCan can? and cannot? methods (the CanCan API) only wraps the #current_user method, since this method is available for most authentication systems including authlogic.

In CanTango we have extended the Can API to wrap all the #current_[user] methods exposed by Devise.

Another issue is how to get the concept of a Guest user integrated. Traditionally, most people have opted to try to tweak Devise methods such as #current_user to return a guest user if no current_user is present. This is an intrusive hack which has its own problems as it can have consequences with other methods that rely on the default logic.

CanTango takes a non-intrusive approach. In the [user]_can? methods, it will attempt to initiate and use a Guest user if no current_[user] can be found. Whatever user is "found" is then passed of to the CanTango::Ability and evaluated with regards to permissions.

CanTango also generates a set of methods of the form session_[user class], fx session_user and session_admin for the above scenario. These methods will return a logged in user for the given user type or if none logged in will return the Guest user for that session.