Lesson Weekend

So far we are only working with two files. Technically, we could build out an entire application with functioning logic using just app.rb. However, we wouldn't be properly separating our concerns. Our code would be messy, verbose, and difficult to test. Sinatra just cares about routing. We shouldn't clutter app.rb with back-end logic, view-related information, and so on. Let's start building our record store now. We'll create a file structure that we'll use for all Sinatra projects.

record_store
├── app.rb
├── Gemfile
├── Gemfile.lock
└── lib
    ├── album.rb
└── views
    |__ layout.erb
└── spec
    ├── album_spec.rb
    ├── album_integration_spec.rb
└── public

Let's go over each of these files and directories.

  • app.rb: This is where Sinatra handles routing. This file belongs in the root directory. We can run our application with the command ruby app.rb.

  • Gemfile: As always, we should include a Gemfile that holds all our gems (including the Sinatra gem). When we bundle our gems, that will create a Gemfile.lock file which shouldn't be edited. (Don't ever create the Gemfile.lock manually; bundling will handle the creation of this file.)

  • lib: This is where we'll store our backend logic. We won't have much logic so we'll only have one file inside this folder for now. Big applications can have many separate files. For now, a general rule of thumb is to have a separate file for each custom class. It's also a best practice to name the file the same name as the class.

  • views: This folder contains our application's HTML. All files in this folder use the .erb extension, which stands for Embedded Ruby. Embedded Ruby files allow us to embed Ruby code within our HTML. We'll also use .erb files with Rails, too. The layout.erb contains HTML that will be included in all our views. We'll also have files for all the views our application will need, including viewing a list of albums, viewing a single album, and editing and updating an album.

  • spec: We should always test our code, including the code we'll put in app.rb. Our album_spec.rb file will include unit tests of all the code included inside our Album class. Our album_integration_spec.rb file will include integration tests. We haven't covered integration tests, but we'll do so later in this course section.

  • public: We'll store all public assets such as images in this directory. This folder can include images, CSS, and JavaScript. For images, we’d add a directory inside this folder called img. We could then access images in the folder in our HTML with the following path: '/img/[image_name_here].jpg'.

Let's also update our Gemfile:

Gemfile
source('https://rubygems.org')

gem('sinatra')
gem('rspec')
gem('pry')
gem('sinatra-contrib')

In addition to the usual suspects, we've added the sinatra-contrib gem. This gem will allow us to make live changes to our app.rb without reloading our files. Without this gem, we'd have to type ctrl + c into the terminal and then re-enter ruby app.rb to launch our server again every time we made a change to the code. That would be very annoying.

In order to utilize sinatra-contrib, we'll need to make a few changes to app.rb:

app.rb
require('sinatra')
require('sinatra/reloader')
require('./lib/album')
require('pry')
also_reload('lib/**/*.rb')

In addition to requiring sinatra, pry, and our album logic, as always, we'll need to require sinatra/reloader. The also_reload method will tell our application which files to reload. Specifically, it says to look in lib, use the globbing pattern ** to look in all directories inside lib, and finally use a wild card * to reload all files with a .rb extension.

Make sure to bundle and then restart the Sinatra server before proceeding.

Project File Structure


This is the structure we'll use for all Sinatra projects.

project_name
├── app.rb
├── Gemfile
├── Gemfile.lock
└── lib
    ├── album.rb
└── views
    |__ layout.erb
└── spec
    ├── album_spec.rb
    ├── album_integration_spec.rb
└── public

Gemfile


Gemfile
source('https://rubygems.org')

gem('sinatra')
gem('rspec')
gem('pry')
gem('sinatra-contrib')

To use sinatra-contrib with app.rb:

app.rb
require('sinatra')
require('sinatra/reloader')
also_reload('lib/**/*.rb')

Lesson 7 of 37
Last updated August 7, 2022