Novellogger — A Reading List Sinatra Web App

Tasked with having to build a simple web app using Sinatra and ActiveRecord, I found myself pacing my living room on a rainy Saturday morning trying to dream up the perfect concept. What would meet all of the requirements of the project — namely M.V.C. architecture, a working database, has_many/belongs_to relationships, C.R.U.D. functionality, etc. — while still being engaging enough in a real world scenario? As I pondered this question, I happened to turn and see the multiple large stacks of unread books sitting idle in my living room and it hit me: an interactive reading list! So I began to build my Sinatra program: Novellogger.

My Novellogger Logo

The purpose of Novellogger is for the user to upload their reading list: books they’ve read, are in the midst of reading, or want to read. They can rate and review them as well and compare their reading list to other users.

Now that I had a concept, my next step was sketching out the structure of the app — the models and their associations, views and controllers. I started with my models: User and Book. A user has many books and each book belongs to a user. Then I had to consider what kind of data needs to be persisted by each model, which I have illustrated below. A user needs to submit login information, while a book has metadata (title, author, etc.) as well as user-specific input, like a user rating and their thoughts on the book (listed below as “user review”).

Then I began listing out all of the routes I would need to complete the project. My focus here was in making sure my app had CRUD functionality and that the routes were RESTful. Once these elements were laid out, I could start building the app.

Scaffolding out my project — making sure that all of the elements of my program were in place, requirements set correctly, etc. — was done with a single command thanks to the Corneal gem. Now it was time to get to work coding. The fun part of this project was finding interesting ways to present the data. Since each book contains an element that notes the reader’s progress, stating either “Unread”, “In Progress” or “Finished”, I organized each user’s reading list by these elements.

The trickiest part of building my app was the edit form. Because I wanted my edit form to give the user both mandatory and optional input fields so that they wouldn’t have to refill the entire form for simple edits lest they pass blank data through the patch request, I had to figure out a simple way of keeping my controller route’s code manageable. At first I had to write a separate line for every single element in the following manner: @book.update(:title => params[:title]) unless !params[:title].empty? knowing that if I had simply written @book.update(params), and upon editing a book left any input fields blank, I would have inadvertently deleted the old information. I knew there had to be a more elegant solution to this problem. Eventually I realized that if I simply set the value of each input in the edit form to it’s previously established data, it would fill the edit form in the browser with that data and would remain assigned as I submitted the patch request. After that it was a simple matter of omitting :_method from the params hash to employ a single update method in place of the eight or so lines I previously needed.

Thankfully building out the rest of the app was a relatively simple endeavor. Once all of the elements were in place I had time to play with the presentation. I messed around with the color scheme in CSS and designed the logo above and viola! I have a finished web app. It’s simple but elegant and I’m happy with it. For now you can check it out by taking a look at my Github repo here: https://github.com/pbrzn/sinatra-novellogger.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Patrick Brennan

Charting my journey from coding noob to professional programmer.