Ruby on Rails is often promoted as an MVC web framework (but in reality, Rails is a Model 2-MVC framework, I will get back to this discussion shortly, though) for the creation of modern, industrial-strength web applications. Ruby on Rails was first released in July 2004 as an open source project, and after about 8 years, it has emerged as one of the most popular web frameworks available. Nevertheless, it’s design pattern, the Model-View-Controller architecture, is older and rooted well outside the web app niche.
In order to understand the MVC framework in depth, we will explore its history first. The Model-View-Controller pattern was formulated in the 1970s by Trygve Reenskaug as part of a smalltalk system being developed at Xerox PARC. This was long before the World Wide Web saga and even before computers became personal. The smalltalk system with MVC design pattern focused on separation of concern, a design principle on which all modern web frameworks base their prioritization. They successfully separated the data model (the data processing part) from the content and content from presentation. They also implemented an intermediate driving force which was the first-in-command. Although it had some downsides, it attracted web developers, resulting in many early web frameworks using the MVC design pattern (and obviously evolving into a de facto standard for building Web applications).
MVC Framework in Ruby on Rails
Navigate to a rails application root and run
ls app/assets helpers mailers models controllers views
As a rails developer, you’ll be spending a significant amount of time working with the
app directory. As highlighted above, this is also where your app’s models, controllers and views that are fundamental to any application based on MVC architecture reside. If you’re wondering how this design architecture works, here is a short overview to help get you started.
- Consider that the browser makes a request for http://localhost/page/show/47. This request is sent on your behalf when you click a link or type a URI in the address bar.
- Rails matches your request to a specific controller using the ‘config/routes.rb’. In our case (http://localhost/page/show/47), Rails routes ‘/pages/show/47′ to the ‘show’ method in the Pages controller and passes an argument, id: 47.
Controlleris a ruby class in which several methods (functions) are defined for parsing the user request. Think of the Controller as an inconsiderate project manager who likes to get things done, one way or another. It simply divides and assigns the work to its employees in succession. It gives out orders and the employees are obliged to take up the order and return something. So, the controller’s show action asks the
Pagemodel to retrieve the page with id: 47 from the database. Controllers can do much more than handling user requests, though.
- Models do the hard labor behind the scenes, and are often praised for their dexterity and proficiency. A Model, in its true sense, represents the data and the business logic of your application. Models usually define how the data gets manipulated. But in Rails, we have an ORM (object-relational mapping, you can read more about it here) named ActiveRecord that binds together business objects and database tables to create a persistable model. For simplicity’s sake and since Rails implements ActiveRecord out of the box, we shall use ActiveRecord models and models synonymously.
In Rails, models are ruby classes that interact with the database. Yes, they virtually talk to the database (doesn’t that sound a bit spooky?). Models deal with data validation, association, transaction and much more. Since they are closely coupled with the database, models can manipulate data records and perform SQL queries. Rails is all about convention rather than configuration. Hence most of the time you’ll find a table in the database and a corresponding model in your app with the same name.
- In our case, the model would retrieve page 47 from the database.
- The Model returns the retrieved data back to the controller and the controller captures the data in a temporary memory location.
- The controller returns the HTML/XML and metadata back to the browser which gets displayed on your screen.
Note: I’ve intentionally left Web servers out of the above discussion to keep it plain and simple. Web Servers such as nginx and Apache act as invisible gateways that bridge the browser to the application’s controller. Since they are virtually invisible, ignoring this topic won’t do much harm.
Firing up MVC
If you’ve been anxiously waiting to see MVC in action, cheer up! We are about to get going! Open up the console and create a new Rails project.
cd ~rails new mvc_app
Create a controller for our mvc_app.
rails generate controller Pages index new create destroy --no-test-framework
Rails has something magical about it. RoR has a powerful spell that lets you generate controllers, views, models and all of them combined without your having any prior knowledge of how Rails works. ‘rails generate’ is a slick and smart script that assists with your web development experience, and it works out of the box.
The above-listed command generates a
destroy actions. Actions are public methods defined on the controller.
Wow, all we wanted was a controller for Pages, but Rails has made a big deal about it, and now we have several new files. Not to worry, this is essential to getting the controller to work. Now might be a good time to check out our new pages_controller.
class PagesController < ApplicationControllerdef indexenddef newenddef createenddef destroyendend
class PagesController < ApplicationController
tells the compiler that
PagesController is derived from
ApplicationController which, in turn, is inherited from
ActionController::Base class defines several useful methods inherited by all the controllers.
Our controller comprises 4 different actions (methods), but they are empty. In plain Ruby, they wouldn’t do anything, but the scope of Rails is beyond that of ruby. You might have noticed in snippet 1.4 that 4 new views were created in app/views/pages directory, corresponding to each action in the controller.
create app/views/pagescreate app/views/pages/index.html.erbcreate app/views/pages/new.html.erbcreate app/views/pages/create.html.erbcreate app/views/pages/destroy.html.erb
Since the actions are empty, the controller renders the template corresponding to its name. For instance,
index action would render the ‘index.html.erb’ view. So when the user attempts to navigate to http://localhost/pages/index, index action in pages controller gets called. But since index method in pages_controller is empty, index.html.erb is rendered, and the HTML is passed back to the controller which then returns to the browser.
And here’s the newly created index view.
<h1>Pages#index</h1><p>Find me in app/views/pages/index.html.erb</p>
Apart from the placeholder text, there is nothing much to see. Currently our view is just a static plain html file without any dynamic content. We’ll soon introduce embedded Ruby into our views and see how it works out.
We now have a working rails application (although it does nothing useful).
If you can’t wait to see your application live, Rails lets you run the application in the development environment using WEBrick, a Ruby library, and it offers all the basic web server services.
To test your application, run
and navigate to http://localhost:3000/pages/index. It’s very basic, at the moment, but this tutorial’s motive was to get you started with the MVC implementation in Rails.
There is, however, one important question that we have not answered yet. How does the web server dispatch the user request to the intended controller? When the browser requested for http://localhost:3000/pages/index, why did the server end up using index controller action rather than new, create or destroy controller? This is where Rails Routes comes to the rescue. Actions defined in the controller are made accessible to the web server with the help of Rails Routes (config/routes.rb).
MvcApp::Application.routes.draw doget "pages/index"get "pages/new"get "pages/create"get "pages/destroy"
You may recall that when we generated the controller, rails invoked config/routes.rb. This explains how these 4 lines of code got there.
maps requests for the http://localhost:3000/pages/index to the index action in the pages_controller. Since the rule is prefixed with get, its response is limited to GET requests alone. Similarly a request for pages/new would get mapped to the new action.
This article was primarily written with the intention of giving the reader an introduction to MVC architecture and then discussing advanced MVC techniques briefly. But I’ll save it for another post.
Since we’ve come this far, let’s step further down the road and create a Pages resource. Generally speaking, it is a database table and the controller can perform CRUD (create, read, update and delete) operations on records encompassed in that table. In our case, a resource would let you treat Pages as objects that can be created, edited, updated and destroyed. By the end of this tutorial, you’ll have something similar to the table listed below.
A Pages resource lets the user create infinite number of new pages, each having a unique id of its own. You can browse through each page, edit and update them and even delete them. All this is accomplished through a web interface (views).
In the next post, we shall create a model for our app, set up the database and put together some code to have a working Pages resource. Stay tuned.
So, is Rails a MVC framework?
Theoretically, Rails doesn’t adhere to MVC standards. Classic MVC had models that can notify views about the changes directly. But, in Rails, model data gets sent to the views via the controller, and it is the controller that returns the HTML output back to the browser. This closely matches the Model2 design pattern initially developed by Sun Microsystems in the late 1990s for designing Java Web applications. But this wouldn’t bother Rails developers, as long as they have a delicious cup of hot coffee while busy crunching code. :)
Feel free to share your thoughts and comments!