Building a Sinatra course management app

Students can view course catalogue and register for courses!

Having built my first Ruby gem last month, I was excited to plan and start working on my Sinatra portfolio project!

In planning my project, I decided to get hands-on experience working with a client by asking my network if anyone needed a web application complete with a backend database!

It only took a day before my friend Mike reached out to me. Mike is an experienced engineer who is building his brand, MikeWorks, where he offers world-class developer trainings!

MikeWorks website

Mike has developed his website using EmberJS and Phoenix as his backend, and wants to include a course management feature - where users can sign-up and enroll in courses!

Here is a video walk-through of my final app

Course Manager demo video

This was a great project for me to build out the online course management web app using Sinatra! I sat down with Mike for an hour to gather his requirements.

APP REQUIREMENTS

  1. A user is either a STUDENT or an INSTRUCTOR
  2. A user should be able to:
  • Sign-up for a new account
  • Log-in to her account
  • Update her account information and password
  • See a list of instructors and students

3. As a student, a user should be able to:

  • View all courses available
  • Register for a course
  • Review enrollment request
  • Update or delete her existing enrollment requests

4. As an instructor, a user should be able to:

  • View all courses available
  • Create a new course
  • Review the courses she is teaching
  • Update or delete her existing courses
  • Review students’ enrollment request, updating requests to Waitlist or Enrolled status

PLANNING APP STRUCTURE

Following my client’s project specification, I begin planning my Sinatra application.

Firstly, I stubbed out my app structure based on the Model–View–Controller (MVC) architectural pattern.

MVC app structure

MODEL

I created three model classes: User, Course, and UserCourses

As an instructor, a User has many Courses.

As a student, a User has many UserCourses where UserCourse is a join-table that stores User-Course relationships.

VIEW

At the root of the app folder, I created two views: index.erb and layout.erb

  • layout.erb: this file allow common HTML surrounding individual pages (or views) to be shared across all pages. This is where I defined my CSS stylesheet, and HTML <head> and <body> containers.
  • index.erb: this defines my app’s homepage, with links for users to sign-up or log-in to the app.

Views are then grouped within two sub folders: Users and Courses.

As I implement CREATE, UPDATE, READ, DELETE (CRUD) operations on the database, the corresponding views (pages) are created.

CONTROLLER

I created three controllers: ApplicationController, UserController, and CourseController.

ApplicationController: this controller inherits Sinatra::Base middleware, giving me access to useful methods to define my route actions such as GET and HELPERS! This is where I enable sessions and session_secret to encrypt user passwords.

UserController: this controller inherits from ApplicationController, and defines RESTful routes relevant to a User

CourseController: this controller inherits from ApplicationController, and defines REST route actions relevant to a Course

DATABASE

Next, it was time to build out the database!

Using Rake, a Domain Specific Language (DSL) programmed for Ruby developed by Jim Weirich, I defined the database tables for each of my model class (User, Course, UserCourse).

Database tables and seed data, used for database migration

I executed database migration using rake command:

rake db:migrate

In addition, I created sample data for my models in my seed.rb file. Sample data helps to represent what the real application should look like, and is helpful for testing my app’s functionality! I seeded my database using rake command:

rake db:seed

If you are a Mac user, SQLPro is a handy application to manage a SQLite database!

SQLPro’s GUI to review database schema and data!

TESTING

Having learned about writing integration tests with Capybara and RSpec throughout my coursework at the Flatiron School, I wanted to adopt Test-Driven-Development (TDD) process where possible!

Using past lab coursework as a guide, I wrote tests for each of my client’s requirement. This process really helped me define my app functionality, edge cases and state management throughout the app.

State is what an application knows about the user, their current interaction with the application, and other pieces of global information. — Jim Duffy

A user who is a STUDENT will require different state management from an INSTRUCTOR. Referring back to my client’s requirements, here are some examples:

As a student, a user should be able to:

  • Register for a course
  • Update or delete her existing enrollment requests

As an instructor, a user should be able to:

  • Create a new course
  • Review the courses she is teaching

In addition, a user is able to view most of the app’s internal pages (e.g. Course catalogue, user list, logout page) only when they are logged in!

As I developed the app, I thought of more test cases and eventually wrote 49 tests! I’m sure there are more tests I can add :)

Part I of my tests, organized in CRUD operations
Part II of my tests

You can review my test code here.

BUILDING THE APP

Finally, it was time to start building my app!

While the planning stage took 2–3 days, I felt prepared to start coding and building my app. With the tests in place, I had guidelines for building each functionality and refactored my code as I pass each section of tests.

The general process I followed for TDD:

  • Run tests and approach the next failed test
  • Write some code
  • Run tests
  • Refactor code
  • Repeat

As I define new RESTful route in my controller, I will create a corresponding view (erb file). For example, an instructor can create a new course:

Controller: course_controller.rb

View: courses/new.erb

You can view the complete repo here on Github.

STYLING

After passing all tests, it was time to style my app! I have recently learned about Google’s Material Design guidelines:

[Material Design is] a visual language for our users that synthesizes the classic principles of good design with the innovation and possibility of technology and science.

After searching on the web for a suitable framework, I found the MUI CSS framework.

MUI is a lightweight CSS framework that follows Google’s Material Design guidelines. It was designed from the ground up to be fast, small and developer friendly.

MUI framework has great documentation, including code snippet examples and clear instruction for installation and use!

You may need to update bower to the latest version. After that, simply install MUI package with bower:

bower install mui

Then import the MUI SASS colors file and Boilerplate HTML to your project. I added this to layout.erb with an in-line stylesheet:

I really enjoyed working with MUI styles. MUI uses the same grid system as Bootstrap except with the mui- class prefix prepended.

To style form inputs and buttons, simply define the relevant MUI classes!

I am really proud of this project, and learned a lot from it!

Thank you for reading this far, and I’d love to hear your feedback — feel free to share in the comments below!