Getting a Taste of Sinatra

Jasmine Ryon
8 min readMay 15, 2021

I’m about to be three months into my online, part-time, Software Engineering program at Flatiron School on May 22nd. Part-time students graduate in 10 months so my cohort’s graduation date is December 17th, 2021. When I first started I was completely overwhelmed, second guessing if I could really follow through with this program’s difficulties and be comfortable with most of the curriculum being self-taught through online lessons, but I am feeling more at ease as time goes on. I still feel imposter syndrome at times, but I believe that it’s never really going to go away with the consistent evolution of the tech industry; however, when I do feel like I’m not good enough or I don’t feel like I’m going to be able to do my future job well, I remind myself why I started this whole journey in the first place and I know that overtakes that negativity for the most part. I want to be better for my wife, family, future, and myself. Within these three months I’ve learned concepts that I never even knew existed before I got accepted into Flatiron so I’m motivated to continue on this path of self improvement and learning. I want to keep up the momentum I have and keep striving for onwards and upwards regardless of the setbacks. I’m a firm believer that as long as you have the willpower, patience, and discipline, you’ll get to where you want to go.

PROJECT:

Our second project of the software engineering program is to create a CRUD (Create, Read, Update, Delete), MVC (Model, View, Controller) application using Sinatra. Sinatra is a DSL (Domain Specific Language) that is specific to the domain HTTP and utilizes Ruby language to formulate a functioning web app on a rack interface, a middleware between web requests and responses. The gem, Thin, works conjointly with Rack and is a web server that interprets HTTP requests. A web application encapsulates different urls to produce a major application whilst a website is an individual url. By using Sinatra, I can build a static or dynamic web application that I can persist data to and form associations using Active Record. Sinatra and Active Record combined can create a web application that allows data management. The purpose of this project is to create a simple CMS, which is a content management system.

I wanted my custom application to track something that I’m interested in so I decided to create a Coffee Tasting Journal. I’ve always taken note of various coffee bags I’ve purchased so why not make it computer friendly?!

PROJECT PLANNING :

I went about my project planning stages better this time around. I mapped out how a user can navigate through the app by writing everything down. I knew by doing so, it would help me later on when I wanted to create RESTful (Representational State Transfer) routes in my controllers. I knew models were blueprints of how objects look like and how the data in the tables are going to be associated with one another. Views are the only part of the application that a user can interact with directly. The views I created render data to users by showing them what they would like to see; there’s a view for every CRUD action and they include text and styling, either through CSS, HTML, or both. The view, layout.erb, renders content to every page throughout the entire application by yielding to other views. The controllers are bridges between models and views (since models and views should never directly communicate), so a controller sends data from the application to the browser and vise versa. Each model gets its own controller (separation of concerns) just like each model gets its own views and by doing so, it makes it easier to debug, navigate, and organize code. Controllers are responsible for defining routes and the actions of those routes when each route is requested or submitted through forms.

Request/Response Flow

PROJECT BUILDING:

I. *Corneal Gem* - I started off with the Corneal gem, built by a former Flatiron student, that creates the basic structure needed in a Sinatra Application. It creates an app folder, models folder, views folder, controllers folder, db folder, public folder, config folder, environment.rb, application_controller.rb, gemfile, rakefile, config.ru, and readme.md. I deleted the spec folder since I won’t be testing, got rid of some files in the public folder, and added a few gems in my gemfile.

II. *Models, Views, Controllers, Tables* - I created a coffee_contoller.rb and user_controller.rb that handle routes, HTTP verbs, validations, redirections, and flash error messages. Both controllers inherit methods from the main controller, ApplicationController , which inherits its methods from Sinatra::Base and allows access to get and post methods. I created all the views I thought I would need for my routes (which I could add to or delete later if need be), then mounted all my controllers in my config.ru. I created my user.rb and coffee.rb models, which inherit methods from ActiveRecord::Base. A user model has_many :coffees, and a coffee model belongs_to :user. Once my models were created, I used Rake (that works with SQL database) through Active Record by runningrake db:create_migration NAME=create_table to make migration files that let me create attributes for each model. Once that was done, I ran rake db:migrate to run those migrations and create both tables. As you can see in my schema:

schema.rb

III. *Fake Data* - The tables existed but they had no saved data, just column names, so I created a file to have some data to play around with in tux. Once I filled out my seeds file, I ran rake db:seed to persist that data to the database. I used the Shotgun/Thin gems to see the new fake data displayed on my browser and I used the Tux gem to create more new data and test out code in order to achieve what I wanted to do with my controller actions.

seeds.rb

IV. *CRUD Routes* - I created many routes in all controllers, but I’ll focus on my coffee_controller.rb that handles all the routes that a user can create, read, update, and delete a coffee log. For the create route, a user fills out a form with a get request and that data is persisted to the database with a post request once an instance of a coffee is created. For the read route, a user makes a get request either to see all their coffee logs or an individual coffee they made; this is possible due to the Active Record associations made in both models. For the update route, first I added Rack::MethodOverride to my config.ru because it’s required in order for forms to have a _method, allowing put, patch, and delete actions to function. Then I created a method to direct the user if the user is not the owner of that particular coffee log, but if they are, they are able to request and submit the edited form. Active Record provides the update method that lets a user update the attributes of the model from the passed-in hash and saves the record, all wrapped in a transaction. For the delete route, it works in a similar way compared to put and patch routes but instead of updating the instance variable @coffee , the Active Record method, destroy, removes the record from the database. The delete route will only follow through if the user is the same user that created that coffee log originally.

Create & Read
Update & Delete

V. *Validations, Authentication, Sessions* - I made sure to add Active Record validations to both my models in order to validate user input so bad data cannot be persisted to the database. The validations not only pertain to user log in and log out but also to forms where users can create objects so the database will not have blank or duplicate data. The Ruby gem, Bcrypt, provides the ability for a user to sign up, login, and logout, so I implemented has_secure_passwordinto my user model and password_digestas an attribute for a user so passwords can be persisted to the database. Bcrypt keeps track of users using sessions and will always return all the objects that belong to a particular user. Basically when a user submits a login form, the params hash is gone through with key/value pairs and the authenticate method from Bcrypt allows a user to login. I put enable :sessions in my application_controller.rb to be able to manipulate and access sessions to keep track of users. Sessions are hashes that store new sessions inside cookies, which are another hash. The key of the session hash is an attribute of the user, user_id .

Validations
Sessions

VI. *Error Messages* - The bonus of the project was to display validation failures to a user with error messages. It was fun seeing the end results pop up when I tested everything out for this challenge. My first step was adding the gem sinatra-flash . Once I did that, I added a bit of code into my layout.erb (right before my yield block) for the flash messages to be able to work properly. This code snippet popped up right away when I was researching how to implement the new gem:

layout.erb

Flash stores its messages in a hash and so this code shows iteration through each flash key and for each one, it is setting up an alert box and prints out the text associated with that key; basically it’s going over the flash hash and looking at keys and rendering a specific key’s value. Flash messages are a great way to navigate a user through an application so I didn’t mind adding this into the project because it doesn’t leave a user wondering why their input did not work the way they wanted it to. Flash literally tells the user what went wrong. For example, if a user submits the wrong password in order to login or if a user leaves an input field blank, a flash message will pop up above when the user is redirected to the same page.

Flash Message

VII. *CSS* - My last step is to add some styling to my views because my application looks pretty boring as of now. I wanted to make sure I got all the code down first before making it look pretty. Now I can just focus making it look better by adding color and maybe images rather than just leaving it with the buttons I added and organized spacing. I’m going to look into how to go about implementing Bootstrap into my app now, but for the most part my project is done!

--

--