Part of the reason Ruby on Rails became popular quickly is that it takes a lot of the hard work off your hands, and that’s especially true in starting up a project. Rails practices the idea of “sensible defaults” and tries to, with one command, create a working application ready for your customization.
First we need to make sure everything is setup and installed. See the Preparation for Rails Projects page for instructions on setting up and verifying your Ruby, Rails, and add-ons.
With that done we need to create new project in RubyMine. Open RubyMine and…
Preconfigure for selected database and select SQLite3RubyMine will then create a Rails application for you and automatically open the file database.yml. If you were connecting to an existing database you would enter the database configuration parameters here. Since we’re using SQLite3 and starting from scratch, we can leave the defaults. Rails will automatically create our database for us.
Then go to the RUN menu in the menubar and click RUN. The first time you do this it’ll display the Run/Debug Configurations window. The defaults are all fine, but I enable the Run Browser checkbox near the bottom to automatically open the site in my default browser. You can UNCHECK the Display settings before launching checkbox, if present, then hit RUN.
You should then see the server window open at the bottom of RubyMine with your Mongrel webserver starting up. Once it’s started RubyMine will open your default browser. If it doesn’t open for some reason, try loading the address http://localhost:3000/. You should see Rails’ “Welcome Aboard” page. Click the “About your application’s environment” link and it’ll display the versions of all your installed components.
Our blog will be centered around “articles,” so we’ll need a table in the database to store all the articles and a model to allow our Rails app to work with that data. We’ll use one of Rails’ generators to create the required files. Switch to your terminal and enter the following:
cd JSBlogger ruby script/generate model Article
We’re running the generate script, telling it to create a model, and naming that model Article. From that information, Rails creates the following files:
/app/models/article.rb : The file that will hold the model code/test/unit/article_test.rb : A file to hold unit tests for Article/test/fixtures/articles.yml : A fixtures file to assist with unit testing/db/migrate/(some_time_stamp)_create_articles.rb : A database migration to create the articles tableWith those files in place we can start developing!
Rails uses migration files to perform modifications to the database. Almost any modification you can make to a DB can be done through a migration. The killer feature about Rails migrations is that they’re generally database agnostic. When developing applications I usually use SQLite3 as we are in this tutorial, but when I deploy to my server it is running PostgreSQL. Many others choose MySQL. It doesn’t matter — the same migrations will work on all of them! This is an example of how Rails takes some of the painful work off your hands. You write your migrations once, then run them against almost any database.
What is a migration? Let’s open /db/migrate/(some_time_stamp)_create_articles.rb and take a look. First you’ll notice that the filename begins with a mish-mash of numbers which is a timestamp of when the migration was created. Migrations need to be ordered, so the timestamp serves to keep them in chronologic order. Inside the file, you’ll see two methods: self.up and self.down.
Migrations are meant to be symmetric. Whatever a migration changes inside the self.up method should be undone with the self.down method. Frequently in development you’ll think you want the database to look one way, then realize you need something different. You can create a migration to make your changes to the DB, start building, and then revert as necessary.
Inside the self.up method you’ll see the generator has placed a call to the create_table method, passed the symbol :articles as a parameter, and created a block with the variable t referencing the table that’s created. We can tell t what kind of columns we want in the articles table. Well, what kind of fields does our Article need to have? Since migrations make it easy to add or change columns later, we don’t need to think of EVERYTHING right now, we just need a few to get us rolling. Here’s a starter set:
title (a string)body (a “text”)That’s it! You might be wondering, what is the “text” type? This is an example of relying on the Rails database adapters to make the right call. For some DBs, large text fields are stored as varchar, while other’s like Postgres use a text type. The database adapter will figure out the best choice for us depending on the configured database — we don’t have to worry about it.
So add these into your self.up so it looks like this:
def self.up
create_table :articles do |t|
t.string :title
t.text :body
t.timestamps
end
end
What is that t.timestamps doing there? The generator inserted that line. It will create two columns inside our table titled created_at and updated_at. Rails will manage these columns for us, so when an article is created it’s created_at and updated_at are automatically set. Each time we make a change to the article, the updated_at will automatically be…uhhh…updated. Very handy.
Now our migration is done. You might wonder, what about the self.down? Didn’t I say migrations need to be symmetric? If we added something to the self.up it is generally the case that we need to undo that same change in the self.down. However, when the migration is creating a table, the self.down can just drop that table regardless of what columns are inside of it. That’s what the generator has setup for us here, where it just says drop_table :articles.
Save that migration file, switch over to your terminal, and run this command:
rake db:migrate
This command starts the rake program which is a ruby utility for running maintenance-like functions on your application (working with the DB, executing unit tests, deploying to a server, etc). We tell rake to db:migrate which means “look in your set of functions for the database (db) and run the migrate function.” The migrate action finds all migrations in the /db/migrate/ folder, looks at a special table in the DB to determine which migrations have and have not been run yet, then runs any migration that hasn’t been run.
In this case we had just one migration to run and it should print some output like this to your terminal:
== CreateArticles: migrating ================================================= -- create_table(:articles) -> 0.0012s == CreateArticles: migrated (0.0013s) ========================================
It tells you that it is running the migration named CreateArticles. And the “migrated” line means that it completed without errors. As I said before, rake keeps track of which migrations have and have not been run. Try running rake db:migrate again now, and see what happens.
We’ve now created the articles table in the database and can start working on our Article model.
Another awesome feature of working with Rails is the console. The console is a command-line interface to your application. It allows you to access and work with just about any part of your application directly instead of going through the web interface. This can simplify your development process, and even once an app is in production the console makes it very easy to do bulk modifications, searches, and other data operations. So let’s open the console now by going to your terminal and entering this:
ruby script/console
You’ll then just get back a prompt of >>. You’re now inside an irb interpreter with full access to your application. Let’s try some experiments…enter each of these commands one at a time and observe the results:
puts Time.now Article.all Article.new
The first line was just to demonstrate that we can do anything we previously did inside irb now inside of our console. The second like referenced the Article model and called the all method which returns an array of all articles in the database — so far an empty array. The third line created a new article object. You can see that this new object had attributes id, title, body, created_at, and updated_at.
All the information about the Article model is in the file /app/models/article.rb, so let’s open that now.
Not very impressive, right? There are no attributes defined inside the model, so how does Rails know that an Article should have a title, a body, etc? It queries the database, looks at the articles table, and assumes that whatever columns that table has should probably be the attributes accessible through the model.
You created most of those in your migration file, but what about id? Every table you create with a migration will automatically have an id column which serves as the table’s primary key. When you want to find a specific article, you’ll look it up in the articles table by it’s unique ID number. Rails and the database work together to make sure that these IDs are unique, usually using a special column type in the DB like “serial”.
In your console, try entering Article.all again. Do you see the blank article that we created with the Article.new command? No? The console doesn’t change values in the database (in most cases) until we explicitly call the .save method on an object. Let’s create a sample article and you’ll see how it works. Enter each of the following lines one at a time:
a = Article.new a.title = "Sample Article Title" a.body = "This is the text for my article, woo hoo!" a.save Article.all
Now you’ll see that the Article.all command gave you back an array holding the one article we created and saved. Go ahead and create 3 more sample articles.
We’ve created a few articles through the console, but we really don’t have a web application until we have a web interface. Let’s get that started. We said that Rails uses an “MVC” architecture and we’ve worked with the Model, now we need a Controller and View.
When a Rails server gets a request from a web browser it first goes to the router. The router decides what the request is trying to do, what resources it is trying to interact with. The router dissects a request based on the address it is requesting and other HTTP parameters (like the request type of GET or PUT). Let’s open the router’s configuration file, /config/routes.rb.
Inside this file you’ll see a LOT of comments that show you different options for routing requests. Let’s remove everything except the first line (ActionController ...) and the final end. Then, in between those two lines, add map.resources :articles so your file looks like this:
ActionController::Routing::Routes.draw do |map| map.resources :articles end
This line tells Rails to do a lot of work. It declares that we have a resource named articles and the router should expect requests to follow the RESTful model of web interaction (REpresentational State Transfer). The details don’t matter to you right now, but just know that when you make a request like http://localhost:3000/articles/ the router will know you’re looking for a listing of the articles or http://localhost:3000/articles/new means you’re trying to create a new article.
Now that the router knows how to handle requests about articles, it needs a place to actually send those requests, the Controller.
We’re going to use another Rails generator but your terminal has the console currently running. You have two options:
exitI like to have several terminal windows available to me when developing, so I’d always choose the first option.
In your terminal, enter this command:
ruby script/generate controller articles
The output shows that the generator created several files/folders for you:
app/views/articles : The directory to contain the controller’s view templatesapp/controllers/articles_controller.rb : The controller file itselftest/functional/articles_controller_test.rb : The controller’s unit tests fileapp/helpers/articles_helper.rb : A helper file to assist with the views (discussed later)test/unit/helpers/articles_helper_test.rb : The helper’s unit test fileLet’s open up the controller file, /app/controllers/articles_controller.rb. You’ll see that this is basically a blank class, beginning with the class keyword and ending with the end keyword. Any code we add to the controller must go between these two lines, so I like to insert a bunch of blank lines between them so I have room work work and push that final end farther down the page.
The first feature we want to add is an “index” page. This is what the app will send back when a user requests http://localhost:3000/articles/ — following the RESTful conventions, this should be a list of the articles. So when the router sees this request come in, it tries to call the index action inside articles_controller.
Let’s first try it out by entering http://localhost:3000/articles/ into your web browser. You should get an error message that looks like this:
Unknown action No action responded to index. Actions:
The router tried to call the index action, but the articles controller doesn’t have a method with that name. It then lists available actions, but there aren’t any. This is because our controller is still blank. Let’s add the following method inside the controller:
def index
@articles = Article.all
end
What is that “at” sign doing on the front of @articles? That marks this variable as an “instance level variable”. We want the list of articles to be accessible from both the controller and the view that we’re about to create. In order for it to be visible in both places it has to be an instance variable. If we had just named it articles, that local variable would only be available within the index method of the controller.
Now refresh your browser. The error message changed, but you’ve still got an error, right?
Template is missing Missing template articles/index.erb in view path app/views
The error message is pretty helpful here. It tells us that the app is looking for a (view) template in /app/views/articles/ but it can’t find one named index.erb. Rails has assumed that our index action in the controller should have a corresponding index.erb view template in the views folder. We didn’t have to put any code in the controller to tell it what view we wanted, Rails just figures it out.
Let’s create that view template now. In the left pane of your RubyMine window, expand the app folder so you can see views, then expand views. Right-click on the articles folder, select New then File and, in the popup, name the file index.html.erb.
Why did we choose index.html.erb instead of the index.erb that the error message said it was looking for? Putting the HTML in the name makes it clear that this view is for generating HTML. In later versions of our blog we might create an RSS feed which would just mean creating an XML view template like index.xml.erb. Rails is smart enough to pick the right one based on the browser’s request, so when we just ask for http://localhost:3000/articles/ it will find the index.html.erb and render that file.
Now you’re looking at a blank file. Enter in this view template code which is a mix of HTML and what are called ERB tags:
<h1>All Articles</h1>
<ul>
<% @articles.each do |article| %>
<li>
<b><%= article.title %></b><br/>
<%= article.body %>
</li>
<% end %>
</ul>
ERB is a templating language that allows us to mix Ruby into our HTML. There are only a few things to know about ERB:
<% or <%= and ends with %><%, the result of the ruby code will be hidden<%=, the result of the ruby code will be output in place of the clauseSave the file and refresh your web browser. You should see a listing of the articles you created in the console. We’ve got the start of a web application!