Introduction
devise
is the most popular gem in Rails for authentication. However, it's also the most confusing gem for beginners. It is so confusing that it even suggests not using it if you're new to Rails or web development in its readme.
I'd like to show you how to install and set up devise
for its very basic functionalities so you can have a starting point to play around with it.
Environment
- Ruby 3.1.2
- Rails 7.0.4.3
- devise 4.9.2
Steps
Initialize a new Rails app
$ rails new basic_devise_with_rails7
For later use, we also add an index page
$ rails generate controller pages index
It will create
- a new controller,
PagesController
- a new action
index
in PagesController
Set up devise
1. install devise
gem 'devise', '~> 4.9.2'
Then run bundle install
to install it.
2. Setup default settings
devise
cannot be used right after installation. You need to initialize it.
To initialize devise, execute
$ rails generate devise:install
It will also pop up several suggestions for settings. I'm going to list those suggestions and how to deal with them.
Depending on your application's configuration some manual setup may be required:
1. Ensure you have defined default url options in your environments files. Here
is an example of default_url_options appropriate for a development environment
in config/environments/development.rb:
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
In production, :host should be set to the actual host of your application.
* Required for all applications. *
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
* Not required for API-only Applications *
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
For example:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
* Not required for API-only Applications *
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
* Not required *
According to the suggestions above, we can do the following things.
1. Set up default URL for action_mailer
You can add it in config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
2. define a root path in route config/routes.rb
We just added pages/index
in the routes so we can set it as the root path.
Rails.application.routes.draw do
root 'pages#index'
get 'pages/index'
end
3. add flash message templates
We can add the HTML below in app/views/layouts/application.html.erb
to show flash messages.
<body>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</body>
4. No need to customize Devise views
We don't need to customize Devise views because we only need the basic functionality
All settings are ok now!
Login & Sign up
Create User model
We need to choose a kind of Model to be used for authentication, that is, you want who can sign up and log in. That model is usually called User
so we execute:
$ rails generate devise User
It will
- create
app/models/user.rb
- create
db/migrate/2023xxxxxxxxx_devise_create_users.rb
- insert
devise_for :users
intoconfig/routes.rb
Then execute
$ rails db:migrate
Link to Devise pages
We need a link to the login page, so we update the code in app/views/pages/index.html.erb
and make it the Home page
<h1>Home</h1>
<%= link_to 'Sign in', new_user_session_path %>
and start rails by
$ rails start
Open http://localhost:3000, you should see this page:
Yeah, it feels so plain and even ugly. Please don't mind it because it's not a CSS-styling tutorial...
Click Sign in, you should see the login page
We don't have any users at this point so we click Sign Up link and we will be led to the Sign Up page
Register a new user by entering the email and password and then clicking the Sign up button. You will be redirected to the Home index page.
Checkpoint 1
At this point, we can review what we've done so far. Check the database to see what happened there. I'm using DBeaver here see. You can use whatever tool you like.
You can find a users
table is created successfully.
There are many columns in the users
table, but it's easy to know that
-
email
should store the email of a user -
encrypted_password
should store the password word of a user and it's encrypted
Check the content of the users
table, you can find the row of the user we just created with its corresponding data.
Show User information
Click the Sign in link again, it will show You are already signed in
It seems like you will be signed in automatically after signing up successfully so we are redirected to the Home. Whatever, it does not feel right. Since Sign in
is not a valid link, maybe we don't need to see it when we're signed in. We can update the code in app/views/pages/index.html.erb
<% if user_signed_in? %>
<h1>Welcome Home, <%= current_user.email %></h1>
<% else %>
<h1>Home</h1>
<%= link_to 'Sign in', new_user_session_path %>
<% end %>
Refresh the page and get
Checkpoint 2
There are three helpers you can use in controllers and views based on which model is used for devise
. We have set User
so we have:
-
user_signed_in?
return true if now a user is signed in -
current_user
return theUser
instance of the current signed-in user, it'll be nil if there's no signed-in user -
user_session
return a hash session stored in the cookie. We can ignore it for now.
Logout
It would be nice if we can log out and let the page return to its initial state. We can update the code again in app/views/pages/index.html.erb
<% if user_signed_in? %>
<h1>Welcome Home, <%= current_user.email %></h1>
<%= link_to 'Sign out', destroy_user_session_path, data: { turbo_method: :delete } %>
<% else %>
<h1>Home</h1>
<%= link_to 'Sign in', new_user_session_path %>
<% end %>
The page will be like:
Click Sign out button, then you can be signed out!
You can go to Log in page again and login by entering the email and the password.
Checkpoint 3
For signing out, we want to send a DELETE
HTTP request to the server. Rails 7 has taken turbo-rails as default. Therefore, we can add data: { turbo_method: :delete }
to achieve that.
<%= link_to 'Sign out', destroy_user_session_path, data: { turbo_method: :delete } %>
Congratulations! You just finished the very basic usage of Sign Up/Login/Log out by devise
!
Let's review some more details about it in the following sections.
Devise Routings
We use some mysterious paths out of nowhere in the view:
new_user_session_path
destroy_user_session_path
Where are these paths come from?
When we did rails generate devise User
, it inserted devise_for :users
into config/routes.rb
and those paths are generated dynamically.
You can use rails routes
to check what routes that line generates:
Flash messages
Why there was text showed up on the top of the page? For example,
- Welcome! You have signed up successfully
- You are already signed in.
- Signed out successfully.
Do you remember you added
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
in app/views/layouts/application.html.erb
.
It can show messages stored in
flash[:notice]
# or
flash[:alert]
Other
Why do we need to set the default URL for config.action_mailer?
There are several functionalities of devise
will send email to users. For example, it can send a confirmation letter after a user registers to prevent spam accounts.
If you want to deploy it to production and you have a domain can be used then set it in config/environments/production.rb
config.action_mailer.default_url_options = { host: 'your-domain.com' }
Why I need to login by email and why password has to be at least 6 characters long?
rails generate devise:install
generates 2 files:
config/initializers/devise.rb
-
config/locales/devise.en.yml
You can configure all the devise settings indevise.rb
, including iwhether you want to useusername
to log in or set that password must be at least 8 characters long.
Conclusion
devise
is not a simple gem to learn and use at this moment. However, it's a very powerful tool. If you only run Rails as an API server, it can also support JWT-based authentication. You can check out its wiki page to learn more about it https://github.com/heartcombo/devise/wiki/How-Tos
I hope this article can help you begin the journey with devise
.
Code
All the code can be found at https://github.com/kevinluo201/basic_devise_with_rails7
Top comments (2)
Great explanation. Keep up the good work.
Great