Probably there are not many cases where one wouldn't wont their users to have email addresses. Nevertheless, I had exactly this situation recently. It was quite a challenge (for me at least) to figure out all the things one needs to change in Devise, so as not to expect users to provide an email upon registration and sign-in and to work properly. Finally, I was able to set it to work properly and decided to save you the trouble, in case some of you have a similar setup.
Allow normal users to authenticate with username only, while keeping email authentication for admins in ActiveAdmin
Scenario
You are using ActiveAdmin (AA), Devise, Rails 4 and Ruby 2. You have two models/AA resources - AdminUsers (created by default after installing AA) and Users (generated using Devise). You want your users to be able to login only with username and not have the email attribute at all. At the same time you want your admins to be able to log-in in the AA backend via email.
Source
You can view the source on Github.
Conventions
I refer to the files unser app/models/
as models and the files under app/admin/
as resources.
Prerequisits:
- Generate a new Rails application:
1
|
|
- Add to Gemfile
1
|
|
- Install gems:
1
|
|
- Install ActiveAdmin:
1
|
|
- Migrate the database:
1
|
|
So far you should have a working app with an admin backend, containing an AdminUsers resource. Test it by starting the server with rails s
, going to http://localhost:3000/admin
and logging in with credentials admin@example.com
and password
.
Actual work
Now comes the real work of generating your user model and doing a few tweaks.
Devise initializer
Modify the Devise initializer under config/initalizers/devire.rb
. In particular, change the following lines to look like this:
1 2 |
|
We we will leave the line:
1
|
|
commented out, as we don't want to change the authentication keys globally. We want our admin users to still be able to log in with email. We will change the authentication keys only within the user model.
Also, uncomment config.scoped_views
and set it to true
:
1
|
|
We need this because we have more than one Devise model (AdminUsers and Users) and we want to modify the Users views. More info here.
User model
Generate the User model:
1
|
|
In the user migration file under db/migrate/20131031100550_devise_create_admin_users.rb
replace :email
with :username
so that you have the folloing two lines in the file:
1 2 |
|
Tweak the User model:
- set the desired Devise modules;
- add the authentication keys option;
- overwrite
email_required?
andemail_changed?
.
Your model should look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
I have not included :confirmable
, :registerable
, and :recoverable
as I want all my user management to happen on the backend through ActiveAdmin. What's more, as the User model does not have the email attribute, these modules won't work anyway.
Finally, run the migration:
1
|
|
User resource
Register the User model as a resource in ActiveAdmin:
1
|
|
Modify the User resource to look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Devise views
The Devise views need to be modified in order to reflect that the user is using their username and not their email. First, generate them:
1
|
|
Since I have not included the :confirmable
, :registerable
, and :recoverable
modules, the only relevent view is app/views/devise/sessions/new.html.erb
. You only need to change these lines:
1 2 |
|
Note that f.email_field
needs to be changed to f.text_field
, otherwise in newer browsers the built-in validation won't pass and you'll get error when you enter a username in that field.
To test your work:
- create a new user via the admin back-end;
- go to
http://localhost:3000/users/sign_in
and log in.
Bear in mind that if you have not created a default home page containing a sign out link, you won't be able to log out by just entering http://localhost:3000/users/sign_out
by default, as the sign-out route uses the :delete
HTTP method. As a temporary workaround, in the Devise initializer set config.sign_out_via
to :get
and in routes.rb
change devise_for :users
to
1
|
|
I hope I have saved you some time.