StudioAssistant: A Sinatra-based MVC CMS

Kyle Samuel
5 min readJun 11, 2021

StudioAssistant started as a way to address a very practical problem when it comes to the business of recording music: organizing. With so many different kinds of artists that require their own environment, and the variables inherent to a live recording session, it’s important the studio owner has a grasp of what they’re getting into on any given day.

What is Sinatra?

Sinatra is a DSL (Domain Specific Language) for Ruby that specializes in efficiently giving the developer a “proof-of-concept” for their web app. It is lightweight, especially compared to Ruby on Rails, but it makes up for that with ease of use. It’s built on top of a Ruby web architecture called Rack, and it uses the HTTP requests received from Rack to grab resources from a database and render them to the user through a design pattern known as MVC, or Model-View-Controller.

Initial Design

Though my JobSearch-CLI from my last Flatiron project was something I was proud of, I knew going into StudioAssistant that I needed more of a game plan. MVCs make life easier because they separate our concerns, but if we don’t know the architecture of the system as you’re building it, the different components will struggle to work together and it will be hard to troubleshoot. I used Draw.io to generate the illustration below.

My initial system design and user flow.

My system includes three models, a User model, a RecordingSession model, and a Client model. My user has many recording sessions and many clients through recording sessions. My client has many sessions and many users through recording sessions. My recording session belongs to both user and client. With this design, I was able to emulate a real recording session in my domain, as well as connect each of them with associations via ActiveRecord. Though some of the columns moved around (notably many of my initial client columns became recording session columns) the initial concept remained the same: allow my users to get an overview of any given session and how the client’s needs will affect the work.

Basic App Features

People in music are volatile creatures. I know this because I am one, so I knew how important it would be to keep things simple for my user. My user first creates a profile with a unique email and a password. They then are logged in and taken to this page:

My Recording Session Index — Preloaded with a session.

Here, the user has access to all the sessions they’ve created. When they go to view an individual session, they are taken here:

This is where the user’s recording session data is generated dynamically in a table utilizing Bootstrap. The table is organized by start date. When the user clicks the “View” button, they are given a deeper look at that session, including dynamically generated details that a user might want to know, including whether they need to provide a producer or drums and if the client is bringing a band or not.

From there they can delete their session, create a new session with a current client, and edit or delete their profile.

Front End Views

Because of the lightweight design on the backend, I decided StudioAssistant’s front end needed to share the same philosophy.

StudioAssistant’s welcome page.

My favorite part of working on this app was utilizing the Bootstrap CSS framework to build my approximation of elegance. It was incredibly simple to incorporate, and the class driven selectors made it easy to build upon my prior knowledge of CSS. Sinatra’s use of ERBs made it very simple to generate a lot of dynamic content. I wrote methods in my RecordingSession model to generate some of the logic expressed in my views in the spirit of separation of concerns.

I love writing readable method names.

A Word On Sessions

One of the essential aspects of putting together a Sinatra project is its session feature. Sinatra utilizes a type of cookie known as a session to provide context for the HTTP requests it is receiving, namely who is sending the request. A session cookie persists the user’s id through any HTTP request the user makes. Because HTTP requests are stateless, they are unable to make these distinctions, so a session cookie is incredibly important. In fact when you “log out”, you’re simply deleting the session cookie associated with you.

Sessions are off by default, but it’s a simple process to turn them on: simply type “enable :sessions” in your config area in your application controller. What’s more complicated is making sure the user, or anyone, is not able to access and manipulate the session cookie. By default, Sinatra signs each session with a “session secret” through HMAC-SHA1. Unfortunately, Sinatra doesn’t provide much help for actually setting your session secret. It can only generate 32 byte session secrets, and the documentation actually recommends your session secret be 64 bytes or greater.

Thankfully, there’s a couple of gems that can help us out. The sysrandom gem generates a cryptographically sound set of random numbers. This is exactly what we need as far as a password of sorts, but we still need to hide it from the user and the world. The figaro gem generates a file called “application.yml” that stores environment variables while also including the file in .gitignore, so that our sensitive information doesn’t accidentally get uploaded to Github. Storing the sysrandom generated password within application.yml allows us to call it like any other environment variable as ENV[“session_secret”]. Security is key.

Like A Song

One thing that music and software development has in common is the feeling of putting something out that you truly believe isn’t finished. In this case, and given the number of revisions I made while I was putting together the MVP, I see StudioAssistant adding more and more features as I continue through Flatiron School. Namely, I would love to incorporate Client profiles so that StudioAssistant can help musicians find people to record them, as well as incorporating all the different facets of recording music, including remote work, mixing, and mastering.

--

--