Mod 2 at Flatiron is all about frameworks: support software for creating web apps. After being introduced to the Model-View-Controller (MVC) domain model, we spent several days learning Sinatra. When they decided we’d had enough of that (the UN Human Rights Council might’ve intervened), they introduced us to Ruby on Rails. So the final project was to be a web app built on an MVC domain in Rails. Projects had to have at least one many-to-many relationship and at least two forms.

My friend Alex and I decided to create Movie Night Voting Booth, where a group of users can submit movies and then vote them up or down. Presumably, the highest-voted movie is watched.

PROBLEM THE 1st: MVP

If you’re trying to build a Ferrari, your minimum viable product isn’t a wheel. It’s a skateboard.

Our instructors introduced us to the concept of Minimum Viable Product, the absolute bottom-level app that meets the deliverables. We wanted to be able to create a user, the user can enter a movie title, the movie could be voted on, and then the votes could be tallied.

We turned that out in about four hours. (Thanks Rails.) It was ugly. The user interface was the cutting edge of 1997. But it worked.

So we started thinking of ways to make it look like a real web app.

PROBLEM THE 2nd: user accounts

I come from the days of the dumb static website, but that doesn’t cut it anymore; everything has to be customized and personalized. You want the app to know who you are.

Alex and I knew we wanted to keep track of what user submitted what movie, and we wanted to limit votes to one up- or downvote per user per movie, to prevent spamming. We also wanted to implement an admin role for users, someone who could delete movies and decide when the voting was done.

Alex found AccessGranted, a Ruby gem that lets you set up user roles and what the roles have access to relatively easily. You can get pretty granular with the accesses, too; for example, in our case, we wanted the user to be able to create a vote, but reserved read access to the votes for the admin role. If a logged-in user tried to go to votes/tally in the browser, Rails would throw an error.

So that was the User class settled. How were we to populate the Movie class? The MVP version had users typing in names, but I knew there had to be another way.

PROBLEM THE 3rd: so how do you use an API again?

The Movie Database is a community-driven site for information on movies and television shows. Additionally, it offers a very comprehensive API with several modes of getting information, including submitting a search for movie titles. Exactly what I needed.

To get from a user inputting words to search, to parameters that can make an instance of the Movie class, there were many steps.

  1. Turn the search query into something that can be passed into a URL (called ‘slugifying,’ which I just think is a great word).
  2. Interpolate the result into the API endpoint.
  3. Do a GET action using HTTParty and parse the result into something Ruby can work with.
  4. Turn the resulting JSON object into params that can be mass-assigned to a new Movie.

This glosses over the many hours of tears and screams, cursing the inventor of JSON and all his children, and what I’m sure is the beginning of a very exciting ulcer in three to seven years, as well as the palpable relief when I was clued in to the eval function. eval takes a JSON object, escaped characters and all, and turns it into a regular Ruby hash object. It is a handy trick, and one I’m sure to forget in four weeks when I next need it. (Part of my writing all this down is to help remind me of this very thing.)

So that was the backend code, more or less: the logic for restricting votes (one vote per user per movie) was pretty straightforward. Returning the vote tally wasn’t a hard problem either, it just took some custom routing and writing a couple of methods.

But just because the backend’s done, doesn’t mean you’re done.

PROBLEM THE 4th: a pain in my CSS

CSS sucks. I know it’s better than the alternative, but dang, CSS, you’re annoying and hard. I’ve had to work with CSS just enough to know that I care very little about the difference between an em and a px, and that having to think too long about selector specificity makes me mildly nauseous.

Bootstrap is going to add years onto my life that I otherwise would have lost to stress over CSS. Bootstrap will make your views look good just by importing it. You can style farther from there, of course, custom fonts and background images and the like. Bootstrap made styling a lot more straightforward than I feared, and I recommend it without hesitation.

PROBLEM THE 5th: that one last thing

In the MVP version of Movie Night Voting Booth, I used radio buttons in the form for voting. They worked, and I could have lived with it, but really I imagined hitting a button to upvote, preferably with a big green arrow on it.

This was surprisingly difficult to do. Rails has a number of form helpers, and I had the most practice with form_for, so that’s what I was using. Customizing the submit button was not as straightforward as you might think; several doc pages and Stack Overflow answers, and I was ready to give it up.

And then Alex used form_with.

It annoys me more than it should that it worked exactly the same as form_for, but better. Using :type => :image like that with form_for prevented the value from being passed in, which was essential in differentiating between the two submit buttons in the controller. form_with, on the other hand…

BOOM goes the plastic explosive shaped like a gopher

If you’d like to try out Movie Night Voting Booth, you can download it from my GitHub.

PROBLEM postscript: don’t ignore your .gitignore

When creating the project, I was a bit of a doofus and managed to create it all inside a top-level folder, so the file structure ended up looking like this:

movie-night-voting booth
├─┬─app
│ ├──bin
│ ├──README.md #<= auto-generated GitHub README
│ └──et cetera
└──README.md #<= my real README

If you’ve used Git before, though, you know there are also hidden files that normally you don’t have to worry about. One particularly useful one is .gitignore, which sets up a blacklist of directories where changes to files won’t stage them for commits, places like /tmp or /log.

So guess what happens when you’re a doofus who reorganizes your project structure and manages to delete your .gitignore file! You get 2,000 changes staged for committing. (This is not an exaggeration.) Guess what happens when your doofusness intensifies and you push all those changes onto your branch! Git does what you tell it to, and now your remote branch on GitHub has all the changes. ALL THE CHANGES. Everybody ready for the fun part? Guess what happens when you try to merge this branch with master? There are merge conflicts. Two thousand of them. Each of which must be resolved to merge the changes you actually made into the master.

I am not good at Git. This is obvious. If I was much better with Git, I could have resolved this problem without deleting my branch on GitHub and rm -rf-ing my project file on my computer, then re-cloning the master branch. If I was just a little bit better with Git, I wouldn’t have deleted my .gitignore file.

Don’t be like me. Be smart. Don’t delete your .gitignore file. Here endeth the lesson.

Full stack developer