Building an MVC Framework — Part 2

OKONKWO VINCENT IKEM
6 min readJun 19, 2016

--

This is the second part of Building an MVC Framework with Ruby. The topics we’ll cover are:

  • Part 1 — Rack Deep Dive
  • Part 2 — Set up a Basic Framework
  • Part 3 — Autoloading and Utility Methods
  • Part 4 — Better Routing
  • Part 5 — Render, Redirect & Before_Action Methods in Controllers
  • Part 6 — Extract Complexities out of View with Helpers
  • Part 7 — Reduce Rework with Generators
  • Part 8 — Set up ORM for Read/Write to Database
  • Part 9 — Generate Database from Schema
  • Part 10 — Set up Migrations

The source code for this post is available on github.

Set up a Basic Framework

In this post we’ll use the knowledge of rack from the previous post and build a basic framework. We’ll cover the below topics:

  • Set up our development environment
  • Create the framework gem.
  • Set up test with rspec

1. Set Up our Development Environment

Youʼll need:

• Ruby 2.0 or greater
• a text editor(sublime or any other)
• a command-line or terminal
• Git
• Bundler.
• SQLite, will be needed in part 8 to 10

If you donʼt have them, youʼll need to install them. You can install from source, from your favorite package manager, from RubyGems, or you can Google it and follow instructions.

2. Create the Framework gem.

For your framework to be reusable by other applications, you need to package it as a gem. Rails was packages as a gem so that other application can include and build on top of it. We will do the same for our framework. We will be calling our framework zucy.

Create a new gem called zucy

$ bundle gem zucy
Code of conduct enabled in config
MIT License enabled in config
create zucy/Gemfile
create zucy/.gitignore
create zucy/lib/zucy.rb
create zucy/lib/zucy/version.rb
create zucy/zucy.gemspec
create zucy/Rakefile
create zucy/README.md
create zucy/bin/console
create zucy/bin/setup
create zucy/CODE_OF_CONDUCT.md
create zucy/LICENSE.txt
create zucy/.travis.yml
create zucy/.rspec
create zucy/spec/spec_helper.rb
create zucy/spec/zucy_spec.rb
Initializing git repo in /Users/ikem/Projects/zucy

Let’s commit our changes:

$ git add --all
$ git commit -m "initial commit"

2.1 Customize zucy.gemspec File

Make sure to replace “FIXME” and “TODO” in the descriptions, summary and metadata[‘allowed_push_host’] — You can’t build your gem if you have any of them in your gemspec.

Add some development and runtime dependencies.

spec.add_development_dependency "bundler", "~> 1.10"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec"
spec.add_runtime_dependency "rack", "~> 1.0"

Each of these adds a runtime dependency (needed to run the gem at all) or a development dependency (needed to develop or test the gem)

Let’s commit our changes:

$ git add --all
$ git commit -m "update gemspec to reflect the correct description, summary and dependencies"

Letʼs build your gem and install it:

$ gem build zucy.gemspec
$ gem install zucy-0.1.0.gem

2.2 Create the Application Class

Open lib/zucy.rb and paste the code below.

This class is the entry point for all request. You will notice that it has a call method. Some interesting things are happening here. On line 10, a method called get_controller_and_action_for returns the controller and action method to serve the request. On line 11, the controller is instantiated and the action method is invoked via the send method of the controller object. The send method is used to called a method on an object dynamically. You can learn more about send method here. Finally a rack compatible response is returned on line 12.

How exactly is the controller and action gotten? Let’s explore get_controller_and_action_for method.

get_controller_and_action_for method implement’s a very simple routing, so weʼll just get a controller and action as simply as possible. We split the URL on “/”. The “4” just means “split no more than 4 times”. So the split assigns an empty string to “_” from before the first slash, then the controller, then the action, and then everything else un-split in one lump. For now we throw away everything after the second “/” — but itʼs still in the environment, so itʼs not really gone.

The method const_get is a piece of Ruby magic — it just means get me the constant with this name. In this case, we supply the name of the controller we want in string form. Notice that we are requiring the file that contains the constant just before calling const_get

Also, youʼll sometimes see the underscore used to mean “a value I donʼt care about”, as I did above. Itʼs actually a normal variable and you can use it however you like, but many Rubyists like to use it to mean “something Iʼm ignoring or donʼt want.”

On line 19, we check if the action returned from path is nil and if it is, use the verb as the action method to invoke. This will allow us to issue a GET request to /todolist and it will invoke the get method in TodolistController. Also if we issue a GET request to /todolist/name, it will invoke the get_name method in TodolistController.

Commit your changes

$ git add --all
$ git commit -m "create basic application class"

3. Set Up Test with Rspec

Update your zucy.gemspec file with the line of code below.

spec.add_development_dependency "rack-test",  "~> 0.6"

This gem will give us utility methods for testing our rack app.

3.1 Set Up Example Todolist App

Our generated gem has a folder called spec. This is where all our test will reside. Since our gem will be used to build other applications, we will test it against a sample application build from the gem. We will be building a todolist example application. Create a folder called todolist in spec folder and set up it’s folder structure to look like this.

In application.rb, paste the code below.

The second line adds app/controllers folder to the load path so that you can require sample_controller.rb file with just require “sample_controller” without specifying the folder where `sample_controller` lives. In line 5, we created a new class called Application which inherited from our gem’s Application class. This will be the starting point of the application. config.ru and Gemfile are added so that you can run the example application directly using

$ bundle exec rackup

Before running the example todolist application using the above command, paste the code below in config.ru

and update your Gemfile with the code below before running bundle install.

source "https://rubygems.org"gem "zucy"

Commit your changes

$ git add --all
$ git commit -m "create example todolist application"

3.2 Connect Todolist App to spec_helper.rb

Update your spec_helper.rb file in spec folder to look like this.

Paste the code below into zucy_spec.rb

In line 4, we included a module from `rack-test` gem. This gave us access to `get`, `post`, `put` and `delete` you saw in other parts of the test. Also notice line 6–8. The value returned by the app method is the rack app that all request are sent to. In our case, it is the todolist application we just created. Run your test using

$ rake spec

Notice that most of your test failed. This is because todolist app do not have TodolistController. Let’s create it. Create a file called todolist_controller.rb in the controller folder of the todolist app. Paste the code below into the file.

Run your test again. Now all test should be passing. You can test the todolist app manually in your browser by running `bundle exec rackup` when you are in `spec/todolist` folder. Before running the app, make sure you have built and installed the new version of your gem.

Commit your changes

$ git add --all
$ git commit -m "set up testing for rack app and add first set of tests"

With this, we have a fully tested micro framework for building web application. However we still have a long way to go. Keep calm and wait for the next post.

The source code for this post is available on github.

In the next post, we will look at how to autoload classes and we will create some utility methods that will be used throughout this series.

If you liked this, click the💚 below so other people will see this here on Medium. Also, if you have any question or observation, use the comment section to share your thoughts/questions.

--

--

OKONKWO VINCENT IKEM

A journeyman in the field of software craftmanship. A coach. CEO core infrastructure at @ andela. Passionate about education and lifelong learning.