Sinatra Project — FITracker

Kunal Shah
6 min readJan 5, 2021

Back at it again with another Flatiron School project. This project involved using the Sinatra web framework, which is a DSL (domain-specific language) for creating web applications in Ruby quickly.

But wait, why are you using Sinatra if you are writing in Ruby? What about Ruby on Rails?

Ruby on Rails has a lot of “magic” involved when using it and learning Sinatra first helps gain an understanding of how that “magic” is actually working. Using Sinatra requires doing a deeper dive on the Model-View-Controller (MVC) system, and actually requires manually creating routes and connecting them to other pieces of the application.

GIF on GIPHY

My app is a workout/exercise tracker. A user can log in to create, read, update, or delete (CRUD) a workout on the app. In addition to each workout, they can create/update/delete any exercises that were a part of the workout. I did not include a read operation for exercises because the app is set up that when you show a specific workout, all the exercises’ information is shown as well. So how did I make a working app?

Before I did any actual coding, I took the time to look at all the project requirements and see if I could answer them with my project idea.

“Did I have more than one model?” Yes. “Do I have a has_many relationship? Yes, between my user and workout models.

Doing this enabled me to flush out a game plan and set up a list of tasks that I would need to accomplish to make a working project. I can honestly say 50–60% of the project was already done by just doing this.

Corneal
I set up my app using Corneal, a gem created by a Flatiron student that provides all the scaffolding (folders, models, views, controllers) to start building a Sinatra app. Afterward, I got my project connected to my Github so I could push the changes that I made.

Models and CRUD
So for the project we needed at least 2 models with one model being a User that could sign up and/or login to the app. The model is the logic & brain of the app; it interacts with the database and is where data is manipulated. This model needs to be connected to a resource (the other model) that could have CRUD operations done on it. So for my app, I created a User model and a Workout model that had a has_many and belongs_to relationship. To make the app feel more usable, I added an Exercise model that had a has_many and belongs_to relationship with the Workout model. In this case, the exercise model is the resource with CRUD operations that can be used on it.

Thanks to the power of ActiveRecord, by establishing the has_many and belongs_to relationships in the models, it creates all the methods that I needed to have a fully functioning relationship between the models. To utilize all these models, I needed a database to store all the data. I created my tables through my migration files. This would associate each model with the same-named table (the table name is pluralized) and through ActiveRecord, each instance of the model would have attributes that link with the rows of the corresponding table in the database.

Controllers, RESTful Routes, and Validation
Now I was onto the controllers, which is the hub of the app, connecting the models and views. I created 3 additional controllers that inherited from the main application controller, one for each model that I had. The controller is the place that connects my models and views via routes. A route is an HTTP verb paired with a URL matching pattern. Using Sinatra, I had access to GET/POST methods or HTTP verbs. Each route has a block, which contains the controller action. When my application is sent a request by the user, the controller is what handles it by matching the request with the correct route, thus enabling the controller action, which executes the code inside the block.

Using RESTful Routes, I set up my CRUD operations for the exercise and workout models. Only with the user model did I slightly break from the conventional naming of the routes because I just needed users to sign up and log in. While I worked on the controller actions, I also worked on my views (discussed below). Once I had the routes set up and directed to the correct views (which either contained forms to input data or code to show data), I worked on validation by using Sessions. A session is a hash (stores data) that allows a user and server to maintain a semi-permanent connection so that data can be persisted. Thus, if you log in, the server knows you are logged in and you can move freely around the app without having to log in on each new page you go to in the app. To achieve this, I created two helper methods that used the session hash, one that checked if a user was logged in and one that set who the current user was. By using these helper methods, only a user could add or edit a workout or exercise that was their own. This also meant no one else could change your workouts or exercises. Additionally, within the controller, I incorporated logic when a user submitted a form that would check if appropriate fields were filled out correctly. If not, it would redirect them back to the same page and provide an error message (more on this later). This section, other than CSS, took the most time to code. I had to make sure I had the correct routes and redirect routes. Additionally, the data coming from the user needed to be interpreted properly. So while I knew exactly what I wanted in regards to flow, just making sure my variables were consistent and I was using the correct methods to manipulate the data took some time.

Finally, to make the site more secure, I used BCrypt to secure a user’s password. BCrypt runs a hashing algorithm so that the user’s password is not stored as plain text in our database. So if a hacker gets hold of the password, it is a hashed version, which they cannot turn back into the original. Additionally, BCrypt “salts” the password, adding a random string of characters into the hash; thus, if two users had the same password, they would end up as different hashes in the database.

Views and CSS
The views are where we actually render what the user is going to see based on their request. With Sinatra, we use an HTML template called ERB, which allows us to write in Ruby code within the HTML. This allowed me to make my ERB files dynamic and pass through data depending on the user’s request without having to hard code the HTML. The views are all where the forms are written for the user to input in data. The form, when submitted, will send its own request to the app, but as a ‘POST’ request. This HTTP verb lets the app know that new data is being sent to the server from the user. I worked on the views simultaneously with the controllers because I had to ensure my data had a path to follow from input to output.

I spent a decent amount of time styling and it was both fun and frustrating simultaneously. Choosing colors, how you want your webpage to look is fun. However, with little experience using CSS, actually getting elements to move to certain parts of the page, sizing, etc required a lot of Googling and trial & error. And while I got a webpage that stays consistent from page to page, I don’t think I will be earning any awards for UX/UI design (yet!).

Sinatra-Flash
I mentioned earlier that if a user did not fill out something properly, I displayed them an error. To do this, I used a gem called “Sinatra-Flash”, which is based on the gem “Rack-Flash.” It allowed me to create custom error messages by using a hash called ‘flash’ which I could set a key and value in. This ‘flash’ hash was then available for me to use in a views page, which using ERB, I would display the message if there was one present in the hash.

Takeaways

  • Notes, Notes, Notes — planning out my project with what models, controllers, views I would need initially, the relationships between my models, and what data each model (or table) would have really helped speed up the process of setting up my structure initially
  • Become an ActiveRecord Pro — ActiveRecord does so much amazing work behind the scenes, so learning how to fully utilize all that it offers will help so much for Ruby on Rails
  • Errors are your friends! It is telling you how to fix your program. And if you don’t know immediately how to rectify the error, with a little Google searching you can usually solve it and learn something new at the same time.

If you want to check out FITracker yourself, check out my repo here.

The Journey Continues!

--

--

Kunal Shah

Full Stack Web Developer | Flatiron School Software Engineering Graduate | TV Show Enthusiast. Pittsburgh Sports Fanatic.