As a memorandum about Chapter 11 Account Activation
of the Rails tutorial, organize it in your own way.
(* There is no description about the test)
$ rails generate controller AccountActivations
Later, we will need the named root of edit, so we will add resources to the root file so that we can use the named root.
routes.rb
Rails.application.routes.draw do
-
-
resources :account_activations, only:[:edit]
end
Add the three columns needed for the account activation process to the table. First, create a migration file.
$ rails g migration add_activation_to_users
Edit the migration file, add the following 3 columns, and execute rails db: migrate
.
・ Activation_digest
・ Activated
・ Activate_at
add_activation_to_users.rb
def change
add_column :users, :activation_digest, :string
add_column :users, :activated, :boolean, default: false
add_column :users, :activated_at, :datetime
end
Use attr_accessor
to add a virtual column, as you did in Chapter 9 when you added a remember_token
column.
user.rb
attr_accessor :remember_token, :activation_token
Use before_create
to add a method to create activation_token
and activation_digest
in the database before creating a user object.
user.rb
before_create :create_activation_digest
#Create an activation token and digest in the database.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
After that, we will describe the process of sending emails.
Can be created with the rails generate
command.
rails g mailer [mailer name] [mailer method name (action name)] ..
The created file is as follows. ・ Mailer file -Two view templates (text format and HTML format) ・ Test file ・ Preview file
$ rails g mailer UserMailer account_activation password_reset
create app/mailers/user_mailer.rb
invoke erb
create app/views/user_mailer
create app/views/user_mailer/account_activation.text.erb
create app/views/user_mailer/account_activation.html.erb
create app/views/user_mailer/password_reset.text.erb
create app/views/user_mailer/password_reset.html.erb
invoke test_unit
create test/mailers/user_mailer_test.rb
create test/mailers/previews/user_mailer_preview.rb
Open app/mailers/application_mailer.rb
.
Set the sender address of the email.
application_mailer.rb
aclass ApplicationMailer < ActionMailer::Base
default from: '[email protected]' #Specify the sender address of the email.
layout 'mailer'
end
Open the mailer file with app/mailers/[mailer name] .rb
.
In the mailer file, the file that creates the sending process using the mail method
.
Write the mail method for each method and add the sending process.
The main options available in the mail method are: from: Sender email address subject: Email subject to: E-mail destination address etc...
app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
def account_activation(user)
@user = user #Create an instance variable
mail(
to: user.email,
subject: "Account Activation"
)
end
end
Edit the view of the emails sent. (Both text and HTML files) In the view, write the URL required to activate the account.
ruby:account_activation.text.erb
Hi <%= @user.name %>,
Welcome to the Sample App! Click on the link below to activate your account:
<%= edit_account_activation(@user.activation_token, email: @user.email) %>
Looking at the preview, it looks like the following.
ruby:account_activation.html.erb
<h1>Sample App</h1>
<p>Hi <%= @user.name %>,</p>
<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>
<%= link_to "Activate", edit_account_activation(@user.activation_token, email: @user.email) %>
Looking at the preview, it looks like the following.
Once you've created the template, you can preview it.
Next, rewrite the Create action
in the users_controller.rb
file.
[Change before]
users_controller.rb
def create
@user = User.new(user_params)
if @user.save
log_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
[After change]
-UserMailer.account_activation (@user) .deliver_now #deliver_now
↑ Let the user send an email via the account_activation method
of UserMailer
(deliver_now is used when you want to send an email now)
-Since login is not completed at this point, you should not have a session, so delete log_in @user
and change the redirect destination to the root page instead of the user's detail page.
users_controller.rb
def create
@user = User.new(user_params)
if @user.save
UserMailer.account_activation(@user).deliver_now
flash[:info] = "Please check your email to activate your account"
redirect_to root_url
else
render "new"
end
end
Next, rewrite the authenticated method
described in user.rb
.
In the process of account activation, the process of comparing tokens and digests occurs. This process has already been done in "Chapter 9 Advanced Login" (method to compare remember_token
and remember_digest
).
However, in the code written in Chapter 9, only remember_token
and remember_digest
are compared, so it is necessary to rewrite the code so that activation_token
and activation_digest
can also be compared.
Use the send method
for that.
#behavior of send method
>> user = User.first
>> user.activation_digest
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
>> user.send(:activation_digest)
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
>> user.send("activation_digest")
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
>> attribute = :activation
>> user.send("#{attribute}_digest")
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
Use this to rewrite the authenticated method
.
[Change before]
user.rb
def authenticated?(remember_token)
if remember_digest.nil?
false
else
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
[After change]
-Use the send method
to make the code so that both remember
and activation
can be inserted.
user.rb
def authenticated?(attribute, token)
digest = self.send("#{attribute}_digest")
if digest.nil?
false
else
BCrypt::Password.new(digest).is_password?(token)
end
end
By rewriting the authenticated? Method
, you need to rewrite the code that was using the authenticated? Method
.
[Change before]
sessions_helper.rb
def current_user
if (user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
@current_user = user
end
end
end
[After change]
-Rewrite the part inside () of authenticated? Method
.
if user && user.authenticated?(cookies[:remember_token])
↓
if user && user.authenticated?(:remember, cookies[:remember_token])
sessions_helper.rb
def current_user
if (user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
@current_user = user
end
end
end
Then add the edit action
to the account__activations controller
.
First, perform user authentication (authenticate method edited earlier), which is the core of account activation.
Also, check here that the logical value of the activated
column is false
.
@user = User.find_by(email: params[:email])
if @user && [email protected]? && @user.authenticated?(:activation, params[:id])
Once confirmed, update the information in the activated
and activated_at
columns to give the user a session
and activate the account.
Then redirect to the user's detail page.
account_activations_controller.rb
class AccountActivationsController < ApplicationController
def edit
@user = User.find_by(email: params[:email])
if @user && [email protected]? && @user.authenticated?(:activation, params[:id])
@user.update_attribute(:activated, true)
@user.update_attribute(:activated_at, Time.zone.now)
log_in(@user)
redirect_to user_url(@user)
flash[:success] = "Your account is activated!"
else
flash[:danger] = "Invalid link. The account cannot be activated."
redirect_to root_url
end
end
end
You need to add code if the logical value in the activated
column of your account is true.
if @user.activated?
[Change before]
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
if params[:session][:remember_me] == '1'
remember(@user)
else
forget(@user)
end
redirect_to user_url(@user)
else
flash.now[:danger] = 'The email and password combination is invalid.'
render 'new'
end
end
[After change]
def create
@user = User.find_by(email: params[:session][:email].downcase)
if @user && @user.authenticate(params[:session][:password])
if @user.activated?
log_in(@user)
if params[:session][:remember_me] == '1'
remember(@user)
else
forget(@user)
end
redirect_to user_url(@user)
else
flash[:warning] = "Your account has not been activated. Please check your email for account activation."
redirect_to root_url
end
else
flash.now[:danger] = "The email and password combination is invalid."
render "new"
end
end
Finish by refactoring some of the code you created. (The contents of the refactoring code are omitted.)
Ruby on Rails tutorial Chapter 11 Account Activation https://railstutorial.jp/chapters/account_activation?version=6.0#cha-account_activation
Recommended Posts