BANDBUILDER — A Ruby On Rails App
Apologies for beginning this otherwise innocuous programming post with something so heavy, but for millions — potentially billions — of people across the world, it has been exceedingly difficult to navigate the pandemic-era landscape we find ourselves still mired in. The world is changing so rapidly around us, and many of the things we had taken for granted have virtually disappeared or changed irreperably. And just as things start shifting for the better, it begins to shift for the worse again. One step forward, two steps back, repeat.
All of this is a very longwinded and portentous way of saying I miss live music. I missed it well before the pandemic, too, only due to far more positive circumstances. I am a musician who has been playing professionally for over a decade. I took some time off about two years ago when my son was born, thinking, “I’ll get back to it when things calm down a bit.” I was just starting to write new music again, gearing up to put a band together for some shows starting in Summer 2020. Funny, right? Needless to say it’s been awhile since I’ve graced a stage and even longer since I’ve attended a show as an audience member. I miss the feeling of collective joy in making, hearing and feeling music in a tightly packed room. I’m cautiously optimistic now as vaccination rates keep rising and more venues open up, but nostalgia for a hopefully-not-bygone era grips me nonetheless.
This was sitting at the forefront of my mind as I began work on my first Ruby on Rails app. My app needed a strong relational foundation — with many-to-many and has-many-through relationships galore — so I immediately thought of my own real world connections with other musicians, my instrument, and the gigs I miss so much. So once I had a concept, it was on to sketching out my models and associations…
No, this is not Charlie Kelly’s mailroom conspiracy board, though I must say I felt a little like Charlie when I was first sketching out my model relationships. This is mainly because, as you will see, I have two distinct user models that inherit from a parent User model. I did this to allow the user a choice between one of two types of user when first signing up: Music Director or Musician. A Music Director is in charge of creating and managing gigs, while a Musician can be booked for and play on said gigs. Instead of creating two totally separate user classes — which would have made the signup/login process a logistical nightmare — I followed a path of Single Table Inheritance. This means that the database only has one single User table where users are separated by type, and the subclasses inherit from the parent User class so that users of both subclasses have access to the same attributes. The primary drawback to this approach is that since both subclasses are using the same table, they cannot have attributes unique to themselves, so each subclass may have attributes whose values remain nil, but since both of my user subclasses share more attributes than not, this was the most appropriate approach to take. In any case, you can see all of the associations sketched out above. Direct associations are marked with a solid red line whereas any has_many_through relationships are shown with a dotted line going through a join table to connect two models.
Once the models and associations were out of the way I then focused on the basic functionality of my app; building out the routes, controllers and views. While most of the functionality for the app is pretty straightforward — sign up or log in, view your profile, view other profiles or gigs etc. — the hard part was designing the function of creating gigs and booking musicians for those gigs. Creating a gig entails setting a date, time and venue — again, simple enough — but it also entails selecting instruments you would like to populate the band and giving the gig an adjustable budget.
One thing I decided early on in the BANDBUILDER brainstorming process was that I wanted each gig to have a budget attribute that would change once a musician was booked and ‘paid’ the amount listed as the musician’s pay_rate. To accomplish this, I defined a #book_musician method in the Gig class that takes an argument of a musician, and adjusts the budget after creating an association between the musician and the gig. I employed #book_musician in the Gig Controller’s update action (not in the create action, seeing as one of the prerequisites of adding a musician is that there needs to be an instrument role to fill first). Now, once a musician is added to a gig, the gig’s ‘show’ page displays the adjusted budget along with the associated musician!
Additionally, if you are perusing BANDBUILDER as a Musician and happen upon a gig you’re interested in that has an open slot for your instrument, you can request an “audition” for the gig by clicking the Audition button. This creates an Audition instance that is associated with the gig and the musician. The Music Director for the gig will see the audition request on the gig’s show page, and if they like the Musician for the part, the Music Director can book them, which in turn destroys the Audition instance. The Music Director can also deny an audition request by clicking a “Deny Audition” button that also destroys the Audition instance.
Though building out the rest of BANDBUILDER was incredibly challenging and time-consuming, there was surprisingly little drama. No mental breakdowns. No idle threats of tossing my laptop out of a window. Just countless hours of pensively staring at my screen and muttering under-my-breath to no one in particular. I will say, however, that my biggest stumbling block was the task I saved for last: utilizing OAuth third party signup/login. I decided to go with an OmniAuth Google strategy for this task mostly because I had some experience using OmniAuth with Facebook and Github, so I was familiar with OmniAuth in general but I wanted to broaden my horizons by using a different third party. I employed the ‘omniauth’, ‘omniauth-google-oauth2’ and ‘omniauth-rails-csrf-protection’ gems to facilitate everything. Once I had the client ID and secret from Google it was off to the races… or so I thought.
Every time I reached the Google sign-in screen and clicked on my account, I expected to go to my (at this point empty) profile page, only I kept receiving an error stating “No route matches {:action=>”show”, :controller=>”music_directors”, :id=>nil}, missing required keys: [:id]”, which meant that my app was being prevented from creating the new user. With some outside help I came to realize that the problem was in my User validations, specifically my User model’s has_secure_password built-in password validation was the stopping block. I was able to get around this by generating a random 15-character string and assigning it to the user’s password. Problem solved!
And with that, BANDBUILDER is a finished app. You can view my repo at https://github.com/pbrzn/bandbuilder. Thank you for reading!