Working at MVC Inc.

Or creating a Ruby-on-Rails app

When I learned about MVC (the buzzy acronym for models-views-controllers), General Assembly DC instructor Adam Bray used a really awesome analogy that stuck with me and really made the idea stick. I thought it might be equally helpful for others if I shared that analogy, along with a Ruby-on-Rails app I worked on a short while back that you can follow along with.

Close your eyes, because we’re about to take a little journey through your imagination. You’re about to meet a lot of people, so here’s a little flowchart to help guide you on this journey.
Think of this as a map for the mental journey we are able to take.

Let’s say you are sent to MVC Inc., where your friend tells you there’s a great recipe for you to look into for your “new year, new me!” diet.

Upon walking in, you are greeted by a receptionist named Ryan. Ryan asks who or what you’re looking for so that you don’t wander this giant corporation absentmindedly. You let Ryan know that you’re trying to get a turkey recipe because goshdarnit if you can’t keep eating holiday foods after January 2nd. Ryan makes a call and lets you know that someone named Connie can help you out and sends you up to her.

When you get to Connie and let her know that you’d like this turkey recipe please, she nods thoughtfully.

After a second, she picks up her phone and asks someone named Monica to drive out and get the turkey recipe. (“It should be in a big manila folder, look in the holiday section?”)

While Monica (poor girl, must be an intern from the way Connie was talking to her) is driving across town to MVC Inc.’s off-site recipe storage facility to hunt down your turkey recipe, you and Connie bond over the Oxford comma.

After sitting in Connie’s office for a bit, having really said all that can be said about the Oxford comma, Monica finally comes back with a big manila folder full of papers.

“Thanks, I’ll just be on my way then-” You do not get a chance to take the folder from Monica, however, because Connie is aghast at the thought of letting you walk out with a manila folder full of papers. (“Like some kind of animal??”) She calls up Vincent from visuals, hands him the folder, and asks him to make something presentable for you to take home instead. You are left awkwardly waiting in Connie’s office again. But, before long, Vincent (“He likes to be called Vinny, don’t you, Vinny?”) has brought up an admittedly beautiful, laminated printout of the turkey recipe that.

By the time Connie hands this masterpiece to you, you have nearly forgotten the reason you showed up at all. It was all worth it, though, because that printout looks great in your kitchen, was super easy to follow along, and the turkey is delicious to boot.


So how does our awkward visit to MVC Inc. translate to a real MVC app? We’ll be looking at examples from an app I developed in class called Gobblr. (Which, incidentally, contains a lot of delicious holiday recipes if you find yourself craving roast turkey after all.)

Not to be overlooked, Ryan the receptionist is the router in this analogy. Not every MVC system requires a router, but a router will recognize the route of the user’s request and sends that to the controller.

In our example, the controller is none other than Connie. The user request goes through the controller and anything the user gets back comes from the controller as well. The controller is in charge of getting you, the user, what you want.

In Gobblr, our recipe controller looks a little bit like this:
# app/controllers/recipes_controller.rb
class RecipesController < ApplicationController

# index
def index
@recipes = Recipe.all
end

# new
def new
authenticate_user!
@recipe = Recipe.new
end

# create
def create
authenticate_user!
@recipe = current_user.recipes.create!(recipe_params)
@amount = Amount.where(recipe_id: params[:id])
redirect_to recipe_path(@recipe)
end

#show
def show
@recipe = Recipe.find(params[:id])
@amount = Amount.where(recipe_id: params[:id])
end

# etc. etc.

However, the controller does not directly touch the data. That responsibility fell to Monica, who represents our model. The controller tells the model what to look for in the database. The model, knowing what type of information to look for, fetches it and returns it to the controller.

In Gobblr, our recipe model looks like this:
# app/models/recipe.rb

class Recipe < ActiveRecord::Base
belongs_to :user

has_many :amounts
has_many :ingredients, through: :amounts

has_many :favorites
has_many :favorite_users, through: :favorites, source: :user

end
Gobblr uses an ORM called ActiveRecord that you can read more about here.

You’ll remember that you didn’t get the recipe immediately upon that point. That’s because the controller does not just give you raw data. The controller takes what the model fetched and sends it to the view, represented by Vincent from visuals. The view takes what the controller gives it and renders it into what will eventually be delivered to you, the user. (In the case of our Ruby-on-Rails app, the view will do this using embedded Ruby, or ERB, to produce an HTML page in your browser.)

The view is not to be undervalued because without it, our data would just be returned to us in a mess of SQL or however your raw data is stored. The view is what makes your app look useful at all! In Gobblr, a recipe’s SHOW view looks a little like this:
# app/views/recipes/show.html.erb

<%= image_tag @recipe.photo, class: "recipe-photos" %>

<h3>Ingredients:</h3>
<div class="recipe-ingredients">
<ul>
<% @amount.each do |amount| %>
<li><%= amount.ingredient.name %> (<%= amount.quantity %>)</li>
<% end %>
</ul>
</div>

<h3>Directions:</h3>
<div class="recipe-steps">
<%= simple_format(@recipe.steps) %>
</div>

The controller then takes this rendered page and presents it to you, the user, so that you can eat roast turkey year round. Or whatever it is that you asked your app to do.

Here’s a flowchart that might help you visualize what’s going on when you make a request:

I can confirm Google Chrome is not required!

So to refresh:

  1. You walk into a bar. I mean, MVC Inc. I mean, you, the user, make a browser request.
  2. Ryan the receptionist, aka the router, points you in the right direction — the controller.
  3. Connie the controller takes your request and decides what to do with it.
  4. The controller passes along the request to the Monica the model.
  5. The model gets the appropriate data from the database, based on what she knows about the request.
  6. The model brings that data back to the controller.
  7. The controller then sends the data to Vincent the view, who renders the data into whatever you, dear user, will be looking at and passes that back to the controller.
  8. The controller then sends a response back to the browser with what the view wants you to see and what the model got from the database.

And that’s how operations work at MVC Inc. It may seem like a lot of steps, but this separation of concerns helps the app keep everything straight. When you are developing your apps using this architectural system, it can be easy to forget what each component is doing or why you need it. I hope this analogy has helped you as much as it has helped me! (Thanks again, Adam!)


Reference links:

  • To see what a working Gobblr looks like, visit the deployed app here
  • To explore the code behind Gobblr a bit more, visit the GitHub repo here

If you have any questions or suggestions for this analogy or with Gobblr itself, please feel free to leave a comment on this post or leave an issue on the Gobblr repository, respectively. Gobblr is still a work in progress but I’m eager for tips as to how to improve it!