Devise is a complete MVC authentication solution for Rails. It can be used in lieu of building authentication from scratch. This post is an overview of Devise customization solutions that were used in Wikit. Some of the customizations below were also used in Liberty Hawk, but the discussion and code snippets pertain to Wikit.
Including and removing modules (e.g. confirmable and validatable)
Configuring Devise messages in devise.en.yml
Customizing Devise views by using templates to override them – generating these templates via the devise:views generator.
Customizing authentication routing by adding options to the devise_for call in routes.rb
Customizing fields used for authentication – e.g. using a username field instead of the default email field.
Customizing validations when a user signs up for an account by changing configuration options in devise.rb.
What if, instead of just changing the styles of existing forms or adding additional layouts, you want to change where the forms are rendered in your application (e.g. you want sign up and sign in forms located inside another view)? And what are the considerations that follow this new placement? A failed registration will still redirect to Devise's default sign up path (not the new form location you implemented) unless these redirects are updated via a controller. And how do you make sure error messages are displayed on your new view. When I wanted to render devise sign in and sign up forms as partials on the welcome page of my application, Wikit, this was the problem and follow up customization issues that needed to be addressed. The efficacy of the following solutions are limited to the scope in which Devise was used in that application. It has not been tested beyond that (e.g. with models that inherit from another Devise model).
On his blog, J. Fernández offers a solution for showing Devise forms on another page. Devise Wiki posts it as well, with some revisions. As Fernández suggests, I found the use of a partial as the best way to use the form on another view.
The second part of this solution, addressed by Fernández, involves resource mapping to ensure that the methods relied on by the forms are accessible. I placed them in ApplicationController.
Consistent User Flow
The solution above allowed Devise methods to be used from a partial. The remaining issues, however, were maintaining consistency in user flow in the event of failures, and handling error messages. With the above implementation, a failed authentication or registration still redirects to the default Devise paths/views. But if a user fails to authenticate or sign up from the welcome page, they should be redirected to the welcome page and see the error messages for the failure there.
In order to customize the redirect and error message display for failed registration, you can subclass Devise::RegistrationsController and override the create action. The default Devise views use a call to <%= devise_error_messages! %> to display resource.errors, but I wanted to display them to flash[:danger]. The value for flash[:danger] is set inside create, using the map method on resource.errors to display the items in list form.
Also, because html_safe is not preserved from the controller to the view, it is called in application.html.erb instead, <%= flash[:danger].html_safe %>. Redirects after a failed authentication needed to be customized as well. This can be done with a CustomFailure class. As flash[:danger] is used for error messages, that is set in def respond.
Other Customizations: styles, messages, & paths
Other customizations included the following: styling the passwords/new and confirmations/new views to match (but not duplicate) the style of the sign in and sign up forms; removing messages for successful sign up and sign in, by editing them in devise.en.yml; and editing paths for certain links in shared/_links. Additional controllers were also implemented to customize redirects on password recovery and resending confirmation actions.
I hope this post was useful in understanding the how and why of the customized Devise implementations in this portfolio's apps. Even better if you learned something about using Devise forms on different pages in your app, and correspondingly handling paths and Devise messages.