Creating My First Sinatra App

Posted by 81Jeremiah on July 29, 2018

I wanted to create an app that was useful for myself and hopefully also be useful for others. I’ve been working in supply chain for several years and big box retailers (basically any store with multiple locations) all have very specific rules in how product gets shipped in. Rules vary from carton size, to asn details, to how early a delivery request has to made, and the list goes on and on. The app I created is a way to keep track of all these various requirements in a way that accessible for anyone and creates a community where people can come to hopefully get their questions answered.

One of my main goals for this app besides the outlined requirements, was to get comfortable with rspec and creating tests. This was quite a daunting task, so I started with old tests from previous learn.co lessons and starting moving pieces around to fit my needs. This helped me understand the format of tests and by the end of project I was starting to write my own tests. This process gave me a better understanding of creating tests, but most importantly it helped me structure the flow of an app . I found that the actual creation of the app was a lot easier after I understood what I want to the app to do by creating tests. I spent an extra 3-4 days writing the specs before I even started the app, but it was worth it.

The first step was to establish the relationships between the models. I knew there would be USERS and COMPANIES. For this to be a user driven environment I wanted the user to be able to create a company. To achieve this using Active Record I made the user have many companies and made a company belong to a user as well as giving a company a column/ attribute to have a user_id. If a User owned a company it meant that only the user that created the company could edit it. To achieve a community, I knew that there had to be a way for USERS who did not own the company still be able to contribute. To do this, I created a COMMENTS class/moldel. Comments would have user_comments but in order to interact with user and the companies it would need 2 foreign keys(a user id and a company id). In the models for the User class and Company class the comments belong to a user and also belong to a company. To complete the relationship both the User and Company models had to have a have many relationship with the comments. In addition to the relationships I knew Active Record gave me validations. I immediately added validations for a username, email and company name. I later added custom messages to be used with flash messages during rerouting.

With the models established I started on controllers and views. I like to create the controllers and views together and it’s easier to see the process when running shotgun and looking at the app in a browser. The user controller has a few specific features. One, is that it uses sessions to create a cookie to remember the user is logged in. This is used to ensure the user is logged in as well as confirm that a user id equals a session id when editing or deleting content. The user controller is also where the password is authenticated. This is simply done with using the authenticate method provided by the bcrypt gem.

As mentioned above this app allows a user to have many companies and many comments. To accomplish this meant forms and ownership had to be established in the controllers for both models. The views were also written to only allow the user to see links to edit Companies and comments if the user had created the Company or Comment. In the appropriate controllers routes were added to patch and delete, these routes only work if use Rack::MethodOverride is placed in the config.ru file ABOVE where the use and run commands are listed for the controllers. I recommend always adding this before doing anything else, as it could save some debugging time later.

In order to properly follow the REST standards of web development it was very important that the controllers followed a specific pattern. To start, each model has a corresponding controller(ie user model has a user controller). In addition, the same models also have corresponding views. This allows nice clean routes for the http requests. For example, to get a new company form the path would be company/new, to edit a company the path would be company/company-name/edit. Keeping those conventions is essential creating a RESTful app, and keeping each model with its own corresponding controller and views helps keep those paths nice and clean.

Another way to keep with standard of app development is to associate the various http routes with the different elements of CRUD(Create, Read, Update, Delete). The Create method is connected with a route that is formatted as company/new. To Read the index page or a show page with routes of /companies or /company/company-name is used. Update uses a patch requests where the action shows a route of /companies/company-name using the MethodOverride to accomplish a PATCH request. Delete also uses MethodOverride and a path of companies/company-name/delete.

After the app was working, a good portion of time was spent on refactoring. I made a lot of decisions after it was working to make for a better user experience. I added slugs for the company and added a user account page. Making those changes taught me the value of having tests written. With so many different pieces to change, being able to run tests was extremely helpful. I strongly recommend trying to write tests as it helped with creating the original flow of the app and refactoring.

From my continuous google searches while completing this app I noticed that many of these elements are used in rails. I look forward to learning more rails and refactoring this app once again. Specifically I will revisit this app to add a password reset function and a “remember me” check box on the login page. Rails, here I come.