All,
I’ve spent some time getting Devise working as an authentication system
for my end users, and thought I would share how I got it to work.
-
Because Radiant already has a User model, you have to set up Devise
to use a different model for authentication. So, you should choose a
model name, and use that when you install Devise per the directions.
For the purposes of the rest of this explanation, let’s assume that the
model name is CustomUser. -
Do all of your setup for Devise for CustomUser, including setting up
the “devise_for” route (devise_for :custom_user, etc.). I set up my
Devise route in my custom extension’s routes.rb file. -
To protect all of the end-user content, you need to call the Devise
authenticate method somewhere as a before_filter on the SiteController
(I’m executing the line below in my custom application extension):#Use Devise to protect all Radiant-generated end-user content SiteController.class_eval do #Don't authenticate CSS or JS requests, as these will do
redirects
def devise_authentication
authenticate_custom_user! unless params[:url] &&
params[:url].is_a?(Array) && (params[:url].include?(‘css’) ||
params[:url].include?(‘js’))
end
prepend_before_filter :devise_authentication
end
- Once you do this, Devise will be set up to be used to authenticate
against your end-user content. But it won’t work, because both Devise
and Radiant inject a method named “authenticate” directly into the
ApplicationController via module inclusion (luckily, they have different
method signatures, or I would have had a tough time figuring that out).
I attempted to force the segregation of these two authenticate methods
using nothing but fancy metaprogramming to try and change inheritance
hierarchies and what-have-you. Ultimately, I decided that the solution
with the least customization (and thus, easiest to manage over time),
would be to statically bypass the ApplicationController provided by
Radiant in Devise. So…
- Create a new controller named DeviseController that looks like:
class DeviseController < ActionController::Base
layout ‘devise’
end
I put mine in my custom extension’s app/controllers directory, but you
can put it anywhere as long as it is loaded before any of the Devise
stuff.
Also, notice that I built a custom layout for Devise (devise.html.haml)
that looks like my Radiant-managed layout for end-user content.
Yes, that means that changes to the layout within Radiant must be
repeated in this layout file. However, I couldn’t figure out a good way
to share the layouts (even using file_based_layout, I would have had
significant duplication to deal with - I decided to go the simplest
route).
-
Put a copy of the Devise gem into RAILS_ROOT (or
RADIANT_ROOT)/vendor/gems -
In vendor/gems/devise/app/controllers, change each of the five 5
Devise controller’s class definitions so that they descend from
DeviseController, instead of ApplicationController, like so:
class ConfirmationsController < DeviseController
Note that each of the 5 controllers does:
include Devise::Controllers::InternalHelpers
and this is where the conflicting “authenticate” method comes from. But
now, because there’s no more ApplicationController in the hierarchy,
there is no conflict.
- Unfortunately, the redirect on a sign_out does not redirect back to
the log in page by default (I need to resolve this), so I had to do the
following in my DeviseController:
def after_sign_out_path_for(resource_or_scope)
new_custom_user_session_path
end
CAVEATS:
It is very important that the route file that pulls in the Devise route
executes before you attempt to use any of the Devise custom user
specific helpers. The route configuration is what creates all of the
Devise helpers that are then included in various places. If you cause
any helper files to be included before the Devise route is processed,
none of the custom helper methods will be available.
Wes
P. S. It would be interesting to see if it made sense to use Devise for
all Radiant authentication (e.g. both end users and Radiant users), as
Devise has authentication for different scopes baked in from the start.