Through growing up in a family where my parents owned an entertainment booking agency, I learned about many facets of the industry. I’ve even created and maintained their company website for the last 18 years. So, for my final Sinatra assessment project I was inspired to create the “Entertainment Management System,” which can maintain information related to venues, acts, and shows. While it is currently rudimentary in the amount of information it stores, I can envision growing it into something much larger in the future.
A video walkthrough of application is available for viewing above. The source code is available on Github and at the time of this writing, the application is also available for live testing on Heroku here.
The project has the following requirements:
- Build an MVC Sinatra Application.
- Use ActiveRecord with Sinatra.
- Use Multiple Models.
- Use at least one
- Must have user accounts. The user that created the content should be the only person who can modify that content
- Models must have validations to ensure that bad data isn’t created
- Any validation failures must be shown to user with an error message
This application has 3 primary models- Act(s), Venue(s), and Show(s), where a(n)
- Act has many Shows,
- Show belongs to an Act and a Venue,
- Venue has many Acts
Additionally, as the site must incorporate user accounts, a User model was created. As each user must be the “owner” of their records and only the owner can edit or delete a record, an Act/Show/Venue belonged to a user and a user has many Acts/Shows/Venues. These models and relationships are maintained by adding ActiveRecord macros to the application with the records stored in a SQLite database.
Within each model, I also enforced constraints on the inclusion of all attributes for a given object, using the validates_presence_of macro. Consequently, if a user tried to create a record that was missing one or more attributes, the data would not be committed and they would receive an error.
class Show < ActiveRecord::Base validates_presence_of :name belongs_to :act belongs_to :venue belongs_to :user ... class Act < ActiveRecord::Base validates_presence_of :name, :description, :size, :location, :website has_many :shows belongs_to :user ... class Venue < ActiveRecord::Base validates_presence_of :name, :address, :zipcode, :phone, :email, :website has_many :shows belongs_to :user ... end
The majority of the logic for the application lies within the controllers. Each of the above models has its own controller, with the addition of a “sessions” controller that maintains the logic for logging a user in and out of the website.
- Within the controllers, I created logic to perform Create, Read, Update, and Delete (CRUD) capabilities on the Act, Show and Venue models.
- For reading information, each controller would query the appropriate database table via ActiveRecord and retrieve information regarding all venues, or a specific show, or a listing of upcoming shows for a given venue depending on the HTTP verb and route. If the information could be retrieved, it would be stored in an instance variable that would then be accessible to the corresponding view. If it could not be found, the user would be redirected back to the model’s index page
class ShowsController < ApplicationController get '/shows/?', :auth => true do @shows = Show.all erb :"shows/index" end get '/shows/:id/?', :auth => true do @show = Show.find(params[:id]) if @show erb :"shows/detail" else redirect to '/shows' end ...
- In order to perform any of these actions, a user needed to be logged into the site, and validations were added to ensure that if someone tried to “backdoor” into a record by directly accessing a URL, they would be redirected back to the Login page. Additionally, while a logged-in user could view (read) all Act, Show, and Venue records, when the user would attempt to edit/update or delete the record, the controller checked whether the logged in user was the owner; if they were, the view to edit the record would be invoked or the delete action would occur. If they were not the owner, the user would be redirected back to the model index page. I utilized a gem called rack-flash to pass error or success messages to the accordingly to the session, which were in turn, were displayed by the views.
get '/venues/:id/delete/?', :auth => true do @venue = Venue.find(params[:id]) if @venue if @venue.user_id == session[:user_id] @venue.delete flash[:success] = "Venue deleted." else flash[:error] = "You are unable to delete a venue you did not create." redirect to '/venues' end else flash[:error] = "Venue not found." end redirect to '/venues' end
The views to display each index, show, new or edit page were programmed in ERB (Embedded Ruby), which allows the developer to mix HTML with Ruby programming. Once I had an instance variable in the controller, I was able to use Ruby programming in the view to display the information of a single instance of a Show, or iterate over the listing of venues and display the information for each venue. One of the things I wanted to make easy for the user was to allow them to jump from say a show’s detail page, to information about that specific show’s venue or that show’s act. Similarly, on a Venue or Act’s index page, I wanted to list all past and upcoming shows and was able to do this by comparing the current date with the date of a show and ordering the information in ascending order for future shows and descending order for past shows, all within ERB.
<strong>Upcoming Shows</strong> <% @shows.order(show_date: :asc).where('show_date <= ?', Date.today).each do |show| %> ... <% end %>
Additionally, I would conditionally display the value stored in the flash hash if there was a flash message pending output (error or success).
<% if flash[:error] %> <div> <strong>ERROR:</strong> <%= flash[:error] %> </div> <% end %> <% if flash[:success] %> <div> <strong>SUCCESS:</strong> <%= flash[:success] %> </div> <% end %>
Once I had the majority of this view logic determined. I spruced up the site utilizing the Bootstrap front-end framework. I developed a single layout page which contained the majority of page elements including CSS styling elements and JS references, the page header and background design, as well as coding the flash messages to appear directly under the header thereby reducing redundant code from each of the other pages. The layout.erb file then yielded the body to the respective view files for each model. For most of my index pages, I utilized tables to display the data with links to view, edit, or delete a specific record; on my new and edit forms, I used Bootstrap’s form input components to further stylize the site and ensure that the appropriate type of content was being populated in the field (i.e. a field for a URL had a properly formatted web address).
Building an application using a Model-View-Controller (MVC) paradigm is key as it provides separation of concerns, where different files have different responsibilities. In programming the Entertainment Management System, this Sinatra-based project allowed me the opportunity to gain a low-level understanding of this pattern of programming, coupled with my previous learning in building models, collaborating between models, utilizing Object Relational Modeling, and storing and retrieving information from a database via ActiveRecord. This has prepared me well for my foray into the Ruby on Rails curriculum module.