At some point or another, you’ll probably want to customize Devise’s registration process. The stereotypical example is creating an additional record on signup: you’re registering
Users and you want to give each user an
Organization, or something like that. And it works pretty well: you can add an
:organization_name field to the user registration form and create the organization during
class RegistrationsController < Devise::RegistrationsController
def sign_up(resource_name, resource)
user = resource
# create an organization and associate it with the user
organization_name = params[:user][:organization_name]
Organization.create(name: organization_name, owner: user)
# Sign in the user
But I believe that this approach should only be used as a last resort. If you want to run special logic during Devise’s registration process, you’ll open up a can of worms:
- Now, RegistrationsController (whose default purpose is to handle user creation) is also handling
Organizationcreation inside one of its private methods. This is business-specific logic that might not be easy to remember when you need to revisit the controller in the future.
- What happens if there’s an error creating the organization? The
Userhas already been created, but there’s no
Organizationrecord to associate with them. You need to handle this edge case. Will you wipe the user? Redirect them to a different page? Display an error message?
- What if we want to add more to this method? For instance, maybe we want to create a
Roleto associate the user with their organization. What happens if the
Organizationare created but the
In Getting Real, Basecamp writes about letting software “push back”; that is, instead of fighting against software to make it bend to your whims, you bend your whims to fit the software’s design. Since customizing Devise’s
sign_up method is so tedious, why don’t we work within the Rails defaults to create a simpler, more beautiful solution?
Here’s what I recommend: don’t add any custom fields to Devise’s registration form, and don’t run any custom code on
sign_up. Redirect the user to
OrganizationsController#new immediately after they signup, and disguise that page as the second step in your registration process:
“Thanks for joining! Now tell us a bit about your organization.”
Then, you can handle creating the organization inside OrganizationsController – where it should have been done all along. Because we’re playing with the Rails defaults, it’s easy to handle errors, write tests, and modify whatever we need to inside the associated controller. This approach requires less time and effort, and it produces a more stable result.