Rolling with Ruby on Rails Revisited
Pages: 1, 2
Let's Write Code!
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.
- Generate an Empty Rails Web Application.
- Decide whether to use the default database name that Rails chooses or to tell Rails what database we want the app to use.
- If it doesn't already exist, create the database our app will use.
- Decide what feature to work on.
- If they don't already exist, create the tables our app will need to use to produce that feature.
- Generate a code base to use the table(s).
- Repeat steps 4 through 7 until done.
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!
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.