Rolling with Ruby on Rails, Part 2
Pages: 1, 2, 3
Showing recipes in a category
The final task is to add the ability to display only those recipes in a particular category. I'll take the category displayed with each recipe on the main page and turn it into a link that will display only the recipes in that category.
To do this, I'll change the recipe list view template to accept a URL
parameter that specifies what category to display, or all categories if the
user has omitted the parameter. First, I need to change the list
action method to retrieve this parameter for use by the view template.
Edit c:\rails\cookbook\app\controllers\recipe_controller.rb and
modify the list method to look like this:
def list
@category = @params['category']
@recipes = Recipe.find_all
end
Then edit c:\rails\cookbook\app\views\recipe\list.rhtml to look like this:
<table border="1">
<tr>
<td width="40%"><p align="center"><i><b>Recipe</b></i></td>
<td width="20%"><p align="center"><i><b>Category</b></i></td>
<td width="20%"><p align="center"><i><b>Date</b></i></td>
</tr>
<% @recipes.each do |recipe| %>
<% if (@category == nil) || (@category == recipe.category.name)%>
<tr>
<td>
<%= link_to recipe.title,
:action => "show",
:id => recipe.id %>
<font size=-1>
<%= link_to "(delete)",
{:action => "delete", :id => recipe.id},
:confirm => "Really delete #{recipe.title}?" %>
</font>
</td>
<td>
<%= link_to recipe.category.name,
:action => "list",
:category => "#{recipe.category.name}" %>
</td>
<td><%= recipe.date %></td>
</tr>
<% end %>
<% end %>
</table>
There are two changes in here that do all the work. First, this line:
<% if (@category == nil) || (@category == recipe.category.name)%>
decides whether to display the current recipe in the loop. If the category
is nil (there was no category parameter on the URL), or if the
category from the URL parameter matches the current recipe's category, it
displays that recipe.
Second, this line:
<%= link_to recipe.category.name,
:action => "list",
:category => "#{recipe.category.name}" %>
creates a link back to the list action that includes the proper category parameter.
Browse to http://127.0.0.1:3000/recipe/list
and click on one of the Snacks links. It should look like Figure 11.

Figure 11. Showing only snacks
What is it? How long did it take?
That's it! This is a reasonably functional online cookbook application developed in record time. It's a functional skeleton just begging for polish.
Wading through all of the words and screenshots in this article may have obscured (at least somewhat) exactly what this code can do and in what amount of developer time. Let me present some statistics to try to put it all into perspective.
Fortunately, Rails has some built-in facilities to help answer these questions. Open up a command window in the cookbook directory (c:\rails\cookbook) and run the command:
rake stats
Your results should be similar to Figure 12. Note that LOC means "lines of code."

Figure 12. Viewing development statistics
I won't give a detailed description of each number produced, but the last line has the main figure I want to point out:
Code LOC: 47
This says that the actual number of lines of code in this application (not counting comments or test code) is 47. It took me about 30 minutes to create this application! I could not have come even close to this level of productivity in any other web app development framework that I have used.
Maybe you're thinking that this is an isolated experience using an admittedly trivial example. Maybe you're thinking that this might be OK for small stuff, but it could never scale. If you harbor any such doubts, the next section should lay those to rest.
Ruby on Rails Success Stories
Rails is a relatively young framework. As of this writing, it's been barely six months since the first public release. Yet it debuted with such a stunning feature set and solid stability that a vibrant developer community quickly sprang up around it. Within this time frame, several production web applications have been deployed that were built with Ruby on Rails.
Basecamp
From the site itself:
Basecamp is a web-based tool that lets you manage projects (or simply ideas) and quickly create client/project extranets. It lets you and your clients (or just your own internal team) keep your conversations, ideas, schedules, to-do lists, and more in a password-protected central location.
Basecamp was the first commercial web site powered by Ruby on Rails. David Heinemeier Hansson, the author of Rails, developed it. At its deployment, it contained 4,000 lines of code with two months of development by a single developer. In fall 2004, Basecamp stated that it had passed the 10,000-user mark. It considers the actual number of registered users to be proprietary information, but the home page currently states that it has "tens of thousands" of users.
43 Things
43 Things is a goal-setting social software web application. It currently has 6,000 registered users and hundreds of thousands of unregistered visitors. 43 Things has 4,500 lines of code that were developed in three months by three full-time developers.
Ta-da Lists
Ta-da Lists is a free online service
that implements simple, sharable to-do lists. It features a highly responsive
user interface that uses XMLHttpRequest to minimize waiting for
the server. Ta-da Lists came from one developer using one week of development
time producing 579 lines of code.
Snow Devil
Snow Devil is an e-commerce site specializing in snowboards and related equipment. It opened for business only recently, so there is no usage information available at this time. However, it comprises 6,000 lines of code created by two developers in four months.
CD Baby Rewrite
CD Baby is a very successful e-tailer of independent music. In business since 1998, it lists 82,443 artists that together have sold 1.2 million CDs, paying $12 million back into the artists' pockets.
The CD Baby web site previously involved an increasingly unmanageable 90,000 lines of PHP code. Its authors are in the process of rewriting it in Ruby on Rails. It's too early to find any development information, but the owner of CD Baby is publicly blogging about the process and progress of the conversion.
What does this all mean?
When all is said and done, good design will be more important than the framework in determining how your application performs. Think carefully about your database design and how its tables are indexed. Analyze your data access patterns and consider some strategic denormalization of data. Look for opportunities to cache preprocessed data.
Rails has a lot of powerful features to make it easy to prototype and develop applications quickly, which will leave you with more time to think about your application's features and how to tune it for performance.
A Smattering of Ruby on Rails' Features
Rails has many features that I have not used in this two-part article. I'd like to mention a few of them (with links to more information) to give you a more rounded view of the Rails toolkit.
Caching
Caching is cheap way to speed up your application by saving the results of previous processing (calculations, renderings, database calls, and so on) so as to skip the processing entirely next time. Rails provide three types of caching, in varying levels of granularity:
- page caching
- action caching
- fragment caching
Validation and callbacks
To make sure your data is correct and complete before writing it to the
database, you must validate it. Rails has a simple mechanism that allows your
web application to validate a data object's data before the object updates or
creates the appropriate fields in the database. Read the validation how-to or go straight to the validation
API documentation.
ActiveRecord callbacks are hooks into the life cycle of a data object that can trigger logic before or after an operation that alters the state of the data object.
Transactions
ActiveRecord also supports transactions. Quoted straight from the documentation:
Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action. The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and vice versa. Transaction enforce the integrity of the database and guards the data against program errors or database break-downs. So basically you should use transaction blocks whenever you have a number of statements that must be executed together or not at all.
For example, consider the code:
transaction do
david.withdrawal(100)
mary.deposit(100)
end
Testing
Rails was built with testing in mind and provides support for testing your web application. An extensive online tutorial shows how to test a Rails web application.
Generators
Generators are the helper scripts that you can use to generate code for your application. You have already used generators to create new controllers and models, and at the beginning of this article I showed you how to use a new generator to create scaffolding.
Rails also supports user-created add-on generators. For example, Tobias Luetke has written a Login Generator that creates all the code for easily adding authentication, users, and logins to your Rails app.
Security
|
Related Reading
Programming Ruby |
By now, everyone should know the importance of good security in web applications. The Ruby on Rails web site has an online security manual that describes common security problems in web applications and how to avoid them with Rails.
Parting Thoughts
Rails is not your run-of-the-mill, proof-of-concept web framework. It is the next level in web programming, and the developers who use it will make web applications faster than those who don't; single developers can be as productive as whole teams. Best of all, it's available right now, under an MIT license.
I believe that there hasn't been an improvement in productivity like this in recent programming history.
Editor's note: Want more Ruby on Rails? See Ajax on Rails.
Resources
Web sites
- Official Ruby home page
- Official Ruby on Rails home page
- The best way to learn Ruby: read the free book Programming Ruby
- Primary home for open source Ruby projects: RubyForge
- Ruby on Rails open source projects
- Ruby on Rails how-tos
- Four Days on Rails, an excellent next-steps guide to use after "Rolling with Ruby on Rails."
Mailing lists
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.



