Editor's Note: Be sure to check out Rolling with Ruby on Rails Revisited, Part Two, as well as Bill Walton's monthly series, Cookin' With Ruby on Rails. Please note that this tutorial is intended for use with Rails 1.2.6. It has not yet been updated to support Rails 2.x.
Maybe you've heard about Ruby on Rails, the super productive new way to develop web applications, and you'd like to give it a try, but you don't know anything about Ruby or Rails.
That's how the original version of Rolling with Ruby on Rails, published almost two years ago now, began. And it was true. Ruby on Rails (Rails for short) was super productive and it was super fun, too! A community of contributors grew up around it to make it even more productive and more fun! Rails has been growing fast. It has capabilities that you have to see to believe!!! That's what we're here for.
Like the original version, this tutorial will show you how to develop a web-based, database-driven application using Ruby on Rails. Also like the original, it will not teach you how to program in Ruby. On the other hand, if you already know another object-oriented programming language, you should have no problem following along (and at the end you can find links on learning Ruby and lots more).
Before you roll up your sleeves, I want to answer a couple of burning questions.
Ruby is a pure object-oriented programming language with a super-clean syntax that makes programming elegant and fun. Ruby successfully combines Smalltalk's conceptual elegance, Python's ease of use and learning, and Perl's pragmatism. Ruby originated in Japan in the early 1990s. It has become popular worldwide in the past few years as more English-language books and documentation have become available (and its popularity has really taken off since the introduction of Rails!).
Rails is an open source Ruby framework for developing web-based, database-driven applications. What's special about that? There are dozens of frameworks out there, and most of them have been around much longer than Rails. Why should you care about yet another framework?
What would you think if I told you that you can develop a web application at least ten times faster with Rails than you can with a typical Java framework? You can--without making any sacrifices in the quality of your application! How is this possible?
Part of the answer lies in the Ruby programming language. Rails takes full advantage of Ruby. The rest of the answer is in two of Rails' guiding principles: less software and convention over configuration.
Less software means you write fewer lines of code to implement your application. Keeping your code small means faster development and fewer bugs, which makes your code easier to understand, maintain, and enhance. Very shortly, you will see how Rails cuts your code burden.
Convention over configuration means an end to verbose XML configuration files--there aren't any in Rails! Instead of configuration files, a Rails application uses a few simple programming conventions that allow it to figure out everything through reflection and discovery. Your application code and your running database already contain everything that Rails needs to know!
Developers are used to hearing excessive hype accompanying something new. We know. We're developers, too, and we can easily imagine that skeptical look on your face. Super productive. Yeah, right!
We're not asking you to accept it on blind faith. We'll show you how to prove it to yourself.
When you've finished this tutorial, we think you'll be both motivated and ready to learn to "ride the Rails" to similar results yourself. This updated version of the tutorial will produce an application that looks like and has exactly the same features as the original, so we decided to approach it a bit differently. Rather than pretend that we're making this up for the first time, let's pretend that the boss walks into our office just before lunch and says...
Boss: Hey, CB (that's us). I'm in kind of a jam. I really need your help. I'm supposed to do a little dog-and-pony show for my boss tomorrow morning. I've been working up a little app for him on the side. It's kind of a big deal to him and I think he's going to invite some other folks to the demo tomorrow. Maybe his boss. Problem is, I've been using an outside consultant for this, and he must have won the lottery last night. He didn't come in this morning, hasn't responded to my emails, and he's not answering his cell phone. And on top of that, the app stopped working about an hour ago for some unknown reason and I can't even find the source code. CB, this is not the story I want to walk into my boss' office with tomorrow morning. Word around the water cooler is that you've been trying to get some new development tool approved. You say it lets you produce code like ten times faster than the tools we're using now?
CB: Yep. It's called Ruby on Rails, and it's at least 10x. But I haven't had any success with the Ops guys. Can't even get 'em to take a look at it. They're just not enthused about putting anything new into their mix right now.
Boss: CB, I really need to get the situation with this app fixed by tomorrow morning. If you can do that, you can use any tool you want. Just give me a web-based, database-driven app that looks like and acts like the one my boss has already seen. I know that's a lot. I'm probably asking you to work late. Tomorrow morning's really got to be pushing it. I tell you what. If you'll agree to give it a shot, I'll make a phone call, see if I can maybe break the ice for you with the Ops guys.
CB: (sensing an opportunity...) Tell you what, boss. It's almost lunch. If you go get us some pizza, and let me show you how productive Rails can make us, I think we can have you fixed up before lunch is over.
Boss: No way! By the time lunch is over? You are ON, CB.
CB: No sweat, boss. You go get the pizza. I'll get Rails installed. The Ops guys wouldn't let me download the Rails software through the firewall so I brought in a CD this morning. I'll be ready by the time you get back.
Boss: You're going to get a new development environment set up and ready by the time I get back? And then, while we eat, you're going to reproduce an app that I've had a consultant working on for... oh, never mind. I'm not going there. CB, don't get offended but, man, that's pretty tough to believe. I sure hope you're right, though.
So the story begins. The boss has gone to get pizza and we need to get Rails installed in a hurry.
In the original version of this tutorial, Curt showed how to install and configure Rails on a Microsoft Windows platform. In preparation for this update, we discussed how to handle the topic this time. We could do the same thing again, but there've been some complaints about favoring one environment (especially Windows!) over others. Alternately, we could show you how to install and configure Rails on all of them--Windows, Mac, and Linux--but that would take up a bunch of space. Alternately, we could take advantage of the fact that, since the original tutorial, new tools have emerged for each of these environments that make installation and configuration a snap. We could just point you to those resources. Because this last option both gets us off the favoritism hook and requires less effort... well, we're just doing "the simplest thing that could possibly work."
For Windows, use Instant Rails.
For Mac OS X, use Locomotive.
For Linux, try the Rails LiveCD.
Any one of these will have you ready to start developing your first Rails app in less time than it takes to get a pizza delivered.
Boss: OK, CB. Here's the pizza. Now I know I agreed to let you show me how cool your new tool is, but I don't need to understand all the "how's that work?" stuff in detail, so I brought Paul with me, too. I don't mind it if you two dig into the details a little if you don't mind treating it as a sidebar. That OK with you?
CB: Sure, boss. Hi, Paul. Let me just grab a piece of that pie and we'll get started! You said you wanted this to look like the app you've been working on. But you said the app is down now. What do you have for me to work from?
Boss: I found this shot of the main screen (Figure 1) on the consultant's desk.
Figure 1. Our goal!
Basically, the app's supposed to do three things:
Here's a note I found on his desk with the details of how the app works.
That's all we have to go on.
CB: Alright, then. Let's get started! One of the things that Rails really enables, Boss, is an iterative and incremental approach to development. As you'll see very shortly, Rails delivers so much for so little effort that it's hard not to fall into that rhythm. In general, we do the same steps every time we develop a Rails application.
Those are the steps I'll be showing you.
CB: Rails is an application development framework. One of the things that means is that every Rails app has the same basic structure. Rails makes it easy to follow that convention by generating that structure for us when we tell it we want to build a new application. All we have to do is...
Open a Command Prompt window and navigate to where we want to put the app. That's called the Rails Root directory. Its name will vary depending on what OS we're using (among other things), but the names and structure of the directories under there will be the same. So from here on, the paths I talk about will just assume the Rails Root portion.
So what do we want to call this thing?
Boss: We called the first one the cookbook app.
CB: OK. Let's call this one cookbook2.
To create the empty app, we just run the command:
Rails creates a cookbook2 subdirectory (under the Rails Root directory) that contains a complete directory tree of folders and files for an empty Rails application (Figure 2).
Figure 2. Rails at work creating the new application directory
CB: Now that we've built our empty Rails app, we need to let it know what database to use. The Rails convention is that the name of the database we'll use during development is the name of the application (
cookbook2, in this case) concatenated with
_development. I think that'll work fine for us. We'll name our database
cookbook2_development. Also, I've left the password for the development database blank. That's the convention Rails uses when it generates the configuration file for the database. If I had set up the development database to require a password, I would need to tell Rails what password to use to access it. To change either the name of the database we want to use or the password we use to access it, edit ..\cookbook2\config\database.yml. The changes we'd need to make would be pretty self-evident when we looked at the file. Even to you, boss (he says, giving Paul a wink). Because we're OK with using the Rails conventions, we don't have to do even that little bit of configuration.
CB: So now we need to create the
cookbook2_development database. I don't know what you've heard about what I've been saying, Boss, but I want to make sure you know I'm really not pushing Rails to replace our existing tools. Rails' sweet-spot is building database-driven, web-based applications. It's not for getting your toaster to talk to your coffee pot. There are better platforms than Rails for that. In fact...
Paul: Maybe we shouldn't go there right now, CB.
CB: Right you are, Paul. Sorry about that.
Our Rails app needs a database. I've made sure the MySQL engine is running. In the Command window we already have open here, I'll log in as the root user.
mysql -u root -p
Because I didn't set one up for this database, I just hit <Enter> at the password prompt.
And then I create our database:
create database cookbook2_development;
(NOTE: The semicolon at the end is required.)
Because I'm working on Windows, I also need to grant access to the database to a user named
ODBC. If I don't, I'll get an error from MySQL when I try to access it in a Command window. To grant access, I just enter:
grant all on cookbook2_development.* to 'ODBC'@'localhost';
NOTE: If you're not working in a Windows environment (and in some cases, even if you are) this grant may not be necessary. In general, granting unlimited rights on your database to a generic user is not something you do casually. I've included it here to help ensure that you won't encounter an easily avoidable problem while following along with the tutorial.
That's it. We're done with MySQL for now so I'll...
...and return to the operating system (Figure 3).
Figure 3. CB creates a MySQL database for his Rails app on Windows.
CB: OK, Boss. The screenshot you gave me shows that we can create, read, update, and delete recipes. The consultant's note you gave me says we can do the same thing with categories, and that each recipe gets assigned to a single category. Overall, it seems pretty straightforward. Where do you think we should start (CB asks with a little grin to himself. Setting the Boss up is such fun.)?
Boss: Well, CB (he says a little condescendingly), I guess we'd better start by creating a recipe, right? Then we move on to reading it. Then editing it. Then deleting it. Then we need to do the same for the categories, and then we need to hook them together. Finally, we'll dig in to the real coding. Isn't that the way we usually do these things?
CB: Yep. That's the way we usually do these things, Boss (Gotcha! ;-) ) Over. And over. And over again. And that's the point of Rails. We're going to do these same things every time we develop a database-driven application. Let's automate it and get to the real work. Rails assumes we're going to need to create, read, update, and delete any data we tell it we're going to use. Once we have the database tables for it to work with, Rails will generate all the basic code we need to do that. That means we can take bigger bites than we usually do. That's where a lot of the 10x productivity comes from.
This app is really pretty simple for Rails. In fact, it's right in the Rails 'sweet spot', so let's take a big bite.
CB: It's apparent that we'll need one table for recipes and another for categories. The relationship between the two is one-to-many categories to recipes. That means we need to include a foreign key field in the
I'll just open up my favorite text editor and write a few lines of SQL script to create them.
drop table if exists recipes; drop table if exists categories; create table categories ( id int not null auto_increment, name varchar(100) not null default '', primary key(id) ) engine=InnoDB; create table recipes ( id int not null auto_increment, category_id int not null, title varchar(100) not null default '', description varchar(255) null, date date null, instructions text null, constraint fk_recipes_categories foreign key (category_id) references categories(id), primary key(id) ) engine=InnoDB;
CB: Hey, Paul. Remember I said there were a couple of files outside the app directory we'd work on? The SQL script to set up the tables the app uses is one of them. So, Boss. Now I save the file to ..\cookbook2\db\create.sql, and we're ready to create the tables.
In the Command window I'm keeping open, I change into the cookbook2 directory. After I make sure I'm in the cookbook2 directory, I enter:
mysql cookbook2_development <db\create.sql
MySQL executes the script and returns to the command line without telling us anything. That means everything went OK. Our database now contains two empty tables:
CB: Now that we have tables that Rails can look at, we ask it to generate our basic application. In Rails lingo, this is scaffolding. In the Command window, making sure I'm still in the cookbook2 subdirectory, I enter:
ruby script\generate scaffold recipe recipe
This tells Rails to generate the scaffolding: the basic model, controller, and view files for the part of our application that will use the recipes table. You can see that Rails generates quite a few files (Figure 4). In the command line I just entered, I told Rails about two files in particular: the model (the first argument) and the controller (the second/last argument). Rails named the model file recipe.rb and placed it in the ..\cookbook2\app\models\ subdirectory. In like fashion, it named the controller file recipe_controller.rb and placed it in the ..\cookbook2\app\controllers\ subdirectory.
Figure 4. Generating the recipe scaffolding code
Now I do the same thing for categories. Again in the Command window, I enter:
ruby script\generate scaffold category category
This tells Rails to generate the basic model, controller, and view files (Figure 5) for the part of our application that will use the Categories table. As before, Rails will name the model file and place it at ..\cookbook2\app\models\category.rb and will name the controller file and place it at ..\cookbook2\app\controllers\category_controller.rb.
Figure 5. Generating the category scaffolding code
CB: OK, Boss. Everything I've done up to this point has been pretty short and painless, but not particularly exciting. This is where that changes.
Before we move forward, though, let's take a look at exactly what I've done. I entered a total of eight command lines: five MySQL commands and three Rails commands. I created a SQL script with 17 non-blank lines. That's not what I'd really call coding yet, but as you're about to see... well... just hold on to your hat!
CB: I'm going to be using a web server named Mongrel to serve our app. To start it up, in the cookbook2 subdirectory in my Command window, I enter:
When Mongrel has finished starting, it's ready to serve our app.
Figure 6. Starting our web server
CB: You ready?
Boss: Ready for what? You just reminded me that you haven't even written any code yet.
CB: That's right, but that doesn't mean we haven't been productive. Here; take the keyboard. Now open a browser window and point it at http://localhost:3000/category (Figure 7).
Figure 7. Our first Rails app!
Click the link (Figure 8).
Figure 8. New category entry page
Enter a category name and click the 'Create' button (Figure 9).
NOTE: The typical, incredibly astute O'Reilly reader has probably just noticed that CB didn't say "Enter a recipe and click the 'Create' button" here. "Why's that?", you might ask. It won't work yet. Remember: we haven't written any code yet. We won't be writing much, but we do need a few lines to pull it all together. Not many. Just a few. Part Two of this article is now available.
Figure 9. New category added!
Boss: Now, that is way beyond cool--it's awesome! What about recipes?
CB: Just point your browser to http://localhost:3000/recipe (Figure 10).
Figure 10. Empty list of recipes
Click the link (Figure 11).
Figure 11. New recipe entry page
CB: Where's your hat, Boss? It must have been blown away! I told you to hold on to it!
Boss: That is just amazing, CB. I have to tell you the truth. When I agreed to have pizza with you, I really didn't have much faith that you'd actually be able to do this app, start to finish, before lunch was over. I'm starting to get the feeling that maybe you weren't BS'ing me.
CB: And we haven't even written any code yet! You're probably anxious to do that, but before we do, let's have some of that pizza. 'Cause you know, with Rails, we can have our pie and eat it, too!
Continue to Part Two of this article.
Bill Walton is a software development/project management consultant/contractor.
Curt Hibbs has been a consultant to well-known companies like Hewlett Packard, Intuit, Corel, WordStar, Charles Schwab, Vivendi Universal, and more. He now works as a Senior Software Engineer for The Boeing Company in St. Louis.
Return to O'Reilly Ruby.
Copyright © 2009 O'Reilly Media, Inc.