Displaying Error Messages in Sinatra — Step by Step

Luciana
5 min readJun 8, 2021

I’m about to complete my second project as a Software Engineering student at Flatiron School. One thing that I need to mention is how my first project cleared a lot of concepts that I wasn’t getting when I was studying and working on the labs. After that, the second module is much more smooth compared with the first one.

Sinatra is a Ruby web application and my project is called My Bucket List, where the user is able to create a list of goals that he wants to achieve during his life. But in order to create this list, the user must sign in or log in… And how do we display error messages in case the user doesn’t fill up all the fields? Or if the user tries to create a new account with an existing email address? In this blog post, I’ll show how I handled these error messages in my project.

Step 1. Install the rack-flash3 gem.

gem 'rack-flash3'

Step 2. Run bundle to install it.

bundle install

Step 3. Enable sessions inside your configure block.

configure do
set :public_folder, 'public'
set :views, 'app/views'
enable :sessions
set :session_secret, "secret"
end

Step 4. Require rack-flash on the top of the controller file that you’ll use the error message. In my case, it was inside the users_controller.rb

require 'rack-flash'

Step 5. Make sure you have the validates macro methods inside the model file that you want to validate. In my case, it was inside the user.rb file in the models folder. Also, my uniqueness was the email but you might have the username.

class User < ActiveRecord::Base
has_many :lists
has_secure_password
validates :name, :email, :password, presence: true
validates :email, uniqueness: true
end

Step 6. To display the error messages during the sign up process, you’ll first need to check what the user input in the fields. If it was a valid input, the user will be saved and redirect to the /lists route. If it is not valid, we want to show the errors messages.

post '/signup' do
user = User.new(name: params[:name], email: params[:email], password: params[:password])
if !user.valid?
error = ""
user.errors.messages.each do |key, value|
error << "#{key.to_s.capitalize}: #{value.join}\n"
end
flash[:message] = error
redirect '/signup'
else
user.save
session[:user_id] = user.id
redirect '/lists'
end
end

The first part is saving the parameters of name, email, and password inside a local variable called user. If the information that the user inserted is not valid (e.g. left any field blank or the email is already in the system), we want to iterate each of these errors (which comes in a hash with key and value), save inside a string and show up the error messages when redirect again to the /signup page. The else statement is in case the user typed all the correct information, so the user will be saved, the user id will be added to the correspondent session and then redirect to the /lists page.

Step 7. To actually show the error message, you need to add a piece of code inside the correspondent views file — in my case, it was inside the signup.erb in the views folder.

<span class="req">
<% if flash.has?(:message) %>
<%= flash[:message].gsub(/\n/, '<br>') %>
<br>
<% end %>
</span>

If flash has a message, which means an error, then it’ll show up the error messages. I also added the .gsub(/\n/, ‘<br>’) to be able to display each error message in a different line. Below is how the error will show up when the user leave the name and password blank and insert an existing email in the database:

Step 8. To display the error message inside the log in page, you’ll also have to set up your flash message in the post method.

post '/login' do
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect '/lists'
else
flash[:message] = "Login failed: invalid email or password"
redirect '/login'
end
end

In this case, we’re trying to find the user by his email (the unique validation that I set up). If the user is found AND if the password is correct (the .authenticate is a method available through the has_secure_password that is inside our models. Also, remember to install the bcrypt gem and pass the password as password_digest in your database table, to salt it), the user id will be saved inside his session, then redirects to the /lists route. But, if the email address or password is not correct, it will display an error message and then redirects to the login page again — you can customize this error to whatever message you want to display, just remember to don’t be too specific about the error because if someone is trying to hack your system, it’ll be much easier if he knows which one is right and which one is not.

Step 9. Inside the login.erb file in the views folder, you also need to add a conditional code. If the flash has a message argument, the error message that you customized will show up.

<span class="req">
<% if flash.has?(:message) %>
<%= flash[:message] %>
<br><br>
<% end %>
</span>

This is how my error message is being displayed:

PRO-TIP: To show the error message in red, I added a class called ‘req’ in the views/html files and set up a red color and a font-size inside my css file.

.req {
color: red;
font-size: 13px;

[EXTRA] If you also want to handle the url not found error see below.

Step 1. Set up the not_found method inside the helpers method in your application controller file.

not_found do
status 404
erb :error
end

Step 2. Create an error file in your views folder with the message that you want to display.

<h2> Sorry, that page doesn't exist! </h2>

Step 3. I also added the not_found method inside my get /lists/:id method, so if the user tries to go to a list route id that doesn’t exists (e.g. ‘/lists/5000’), it will display the error message.

get '/lists/:id' do
@list = List.find_by_id(params[:id])
if !@list
not_found
end
erb :'/lists/show'
end

This is how it looks like:

And you’re all set! I hope it helps, I tried to write it as clear and easier to understand as possible. Can’t wait to the next module! :)

--

--