Create a Blog Application with Ruby on Rails 7. Third Part: Implement User Authentication

In this blog post, we'll continue developing our blog application by implementing user authentication.

All Parts:

  1. Create a Blog Application with Ruby on Rails 7. First Part: Create the User Resource
  2. Create a Blog Application with Ruby on Rails 7. Second Part: Create a Post Model and a Posts Controller
  3. Create a Blog Application with Ruby on Rails 7. Third Part: Implement User Authentication
  4. Create a Blog Application with Ruby on Rails 7. Fourth Part: Performing Operations on the Post Resource
  5. Create a Blog Application with Ruby on Rails 7. Fifth Part: Implement Authorization

FIND THE CURRENT USER

Let's first define a @_current_user method to find the user with the id stored in the session.

In the application_controller.rb file in the app/controllers/ directory, we add the following private method:

private
def current_user
  @_current_user ||= session[:current_user_id] &&
  User.find_by(id: session[:current_user_id])
end

And we set it as a before filter in the before_action method of the same controller. At the top, we put this line:

before_action :current_user

Next, we will build a mechanism to add and remove the user from the session. Let's generate a Sessions controller. In the terminal, we type:

bin/rails g controller Sessions

In the app/controllers/sessions_controller.rb file, we will define the new and create methods:

def new
end
def create
  user = User.find_by(email: params[:email])
  if user != nil && user.authenticate(params[:password])
    session[:current_user_id] = user.id
    redirect_to root_path
    flash[:notice] = 'Welcome back.'
  else
    redirect_to log_in_path
    flash[:notice] = 'E-mail and/or password is incorrect.' 
  end
end

The authenticate method returns the user if the password is correct and false otherwise. 

We need routes for these actions, so let's add them to the config/routes.rb file:

get 'log-in', to: 'sessions#new'
post 'log-in', to: 'sessions#create'

 In the app/views/sessions/ folder, we create a new view where we'll put the login form and a link to the sign-up page in case the user doesn't have an account:

<p style="color: green"><%= notice %></p>
<h1> Log In </h1>
<p>Or <%= link_to 'Sign Up', sign_up_path %></p>
<%= form_with url: log_in_path  do |form| %>
  <p><%= form.label :email %></p>
  <p><%= form.email_field :email, required: true %></p>
  <p><%= form.label :password %></p>
  <p><%= form.password_field :password, required: true %></p>
  <p><%= form.submit 'Log In' %></p>
<% end %>

Next, we'll create a destroy action so the user can log out. Let's define it in the Sessions controller:

def destroy
  session.delete(:current_user_id)
  @_current_user = nil
  redirect_to root_path
  flash[:notice] = 'Goodbye.'
end

And we define a route to it in the config/routes.rb file:

delete 'log-out', to: 'sessions#destroy'

Finally, let's edit the posts index view to add a login and a signup button if there is no user in the session and a logout button if the user is logged in. Let's put these buttons before the h1 heading:

<% if @_current_user %>
  <%= button_to 'Log Out', log_out_path(@_current_user), method: :delete %>
<% else %>
  <%= link_to 'Log In', log_in_path  %>
  <%= link_to 'Sign Up', sign_up_path %>
<% end %>

Now, in the Users controller, we can redirect the user to the log-in page after a successful registration. Let's modify the create method as follows:

def create
  @user = User.new(user_params)
  respond_to do |format|
    if @user.save
      format.html {redirect_to log_in_path, notice: 'User was successfully created.'}
    else
      format.html { render :new, status: :unprocessable_entity }
    end
  end
end

Post last updated on Dec 17, 2023