This post begins a series of articles about designing, creating, and deploying a Sinatra ToDo app as part of the Flatiron School curriculum
Introduction
Requirements
- Build an
MVC
Sinatra application. - Use
ActiveRecord
with Sinatra. - Use multiple models.
- Use at least one
has_many
relationship on a User model and onebelongs_to
relationship on another model. - Must have user accounts - users must be able to sign up, sign in, and sign out.
- Validate uniqueness of user login attribute (username or email).
- Once logged in, a user must have the ability to create, read, update and destroy (CRUD) the resource that
belongs_to
user. - Ensure that users can edit and delete only their own resources - not resources created by other users.
- Validate user input so bad data cannot be persisted to the database.
- BONUS: Display validation failures to user with error messages. (This is an optional feature, challenge yourself and give it a shot!)
TLTR: Feel free to get the source code.
App Design
The overall plan for this app was to design a web site with a full-stack design, using Sinatra back-end, ERB files to display the front-end, and using Bootstrap to quickly prototype the site.
Based on the requirements the site includes a user account model which allows the end user to create a Todo list secure from other users.
Security
To handle the security of the user model, this app utilizes the bcrypt
gem, and securerandom
to secure the session_secret
. In addition, it uses DOTENV
locally during store the session_secret
, and of course the .env
file is excluded from the .gitignore
.
Data Design
The database design is fairly simple. First the user table uses password_digest
as the password field to utilize the salt and hash provided by bcrypt
:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password_digest
t.timestamps null: false
end
end
end
The table for the ToDo's belongs_to
the user_id
so each list item can be connects to the user:
class CreateTodos < ActiveRecord::Migration
def change
create_table :todos do |t|
t.string :title
t.integer :user_id
t.timestamp null: false
end
end
end
Controller Design
It would be easy to limit the number of controllers but when I was designing the application, I decided to separate the concerns a little more.
The application_controller
controls the app. It includes the security setup, flash messages using rack-flash
, sets the root path, and includes a few helpers methods for the user model. Specifically, the current_user
method which is used to compare the user and session_id to the todo item later in the source code.
def current_user
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
end
The sessions_controller
validates the user login:
post '/login' do
user = User.find_by(name: params[:name])
if user&.authenticate(params[:password])
session[:user_id] = user.id
redirect '/todos'
else
flash[:danger] = 'Invalid login credentials!'
redirect '/login'
end
end
The new user account creation is handled in the user_controller
. Therefore, exiting accounts and new accounts have their own separate controllers:
post '/signup' do
@user = User.new(params)
if @user.save
session[:user_id] = @user.id
flash[:success] = 'Successfully created user account.'
redirect '/todos'
else
flash[:danger] = 'Please enter valid registration data!'
redirect '/signup'
end
end
The todos_controller
, well you guessed it 🤔 handles the Todo list items.
get '/todos' do
if logged_in?
@user = User.find(session[:user_id])
@todos = Todo.where(user_id: current_user)
erb :'/todos/index'
else
redirect '/login'
end
end
It is in this method that the current logged in user is retrieved and compared to the user_id
of each ToDo item. Based on the associations in the database tables, this is the method would pulls together the corr3ct list.
In the next article I will write about the challenges to deploy to Heroku
Top comments (0)