At the Forge - Ruby on Rails
Ruby, an interpreted programming language that looks and feels like a cross between Smalltalk and Perl, has been around for about ten years. Ruby has been gaining in popularity over the last few years, partly because of the release of English-language books and documentation. In addition, programmers have become more interested in finding an alternative to Perl and Python for their general-purpose programming needs.
Ruby's popularity might have continued to grow slowly were it not for Ruby on Rails, a Web development framework that has become the focus of enormous attention. Everyone in the Web development world seems to be talking about Rails; magazine articles, blog postings, conference tracks and even some new books all are dedicated to Rails. Rails is supposed to be elegant, easy to use and easy to modify. Even developers with no previous Ruby experience are switching to Rails.
Does Rails live up to the hype surrounding it? To a large degree, I believe the answer is “yes”—it has a relatively shallow learning curve, it connects easily and quickly to relational databases and it makes the creation of many small- and medium-sized sites faster and easier than I would have expected. But, of course, no framework is perfect, particularly one that was released publicly only one year ago. It remains to be seen if Rails can hold up against more established technologies on several different fronts.
This month, we begin to look at several aspects of Ruby on Rails, so you can decide for yourself if my assessment is accurate. We begin by installing and configuring a basic Rails application. Over the next few installments of At the Forge, we will extend our application in several different ways, considering the ways in which Rails allows us to create and modify our applications.
The first step in creating a Rails application is to install Ruby and then Rails itself. Most modern Linux distributions come with Ruby, although only the latest released version as of this writing (1.8.2) works with the most recent version of Rails (0.12.1). New versions of Rails have been coming out frequently, which means that one or both of these versions might have changed by the time you read this.
Assuming you have installed Ruby, you next need to install Gems. It provides access to the Ruby Gems library, which is something of a cross between SourceForge and Perl's CPAN (see the on-line Resources). Download and unpack the most recent .tar.gz file:
tar -zxvf rubygems-0.8.10.tar.gz
Enter the directory as the root user and type:
ruby setup.rb all
This installs the entire Gems package. Among other things, this installs the gem program in /usr/bin. You then can install Rails, which is distributed via Gems, with the following command:
gem install --remote rails
As with such systems as CPAN and Debian's apt, the gem program is smart enough to identify and download any dependencies it might encounter. By default, you need to explicitly answer “y” when asked if you are interested in installing any dependencies. Because Rails depends on a number of other packages, you should be sure to answer “y” when prompted.
When you are returned to the shell prompt, you can assume that Rails has been installed. However, this is not quite enough. If you are interested in working with a relational database, you also need to install a database interface library. Because I work with PostgreSQL, I installed the pure Ruby client, called postgres-pr:
gem install --remote postgres-pr
Somewhat confusingly, there also is a set of PostgreSQL client libraries (called postgresql) that can be used with Ruby. However, it seems as though most Rails developers are working with the postgres-pr library, at least for now.
Once Rails is installed, we can create a simple “Hello, world” program. To do this, we use the rails command, which is installed in /usr/bin/ by default. Because our example application is a Weblog, we call the application blog. For reference, the name of the application doesn't have to be linked to the name of the URL under which it will appear. Type:
rails blog
Running this produces a fair amount of output, listing the files that have been created on our filesystem. When we give only a single name, blog, the application is created inside of a directory with that name. We can keep all of our applications inside of a single container directory, such as ~/Rails, with:
mkdir ~/Rails rails ~/Rails/blog
If we look inside of the newly created application directory, we see a number of directories and files. The script directory contains administrative programs, written in Ruby, of course. The public directory contains static HTML files, as well as images, stylesheets, JavaScript code and templates that you may use in your application.
The directory you are mostly likely to work with is app, which contains the application itself. The app directory contains subdirectories named models, views and controllers. This design reflects the fact that Rails uses the MVC (model/view/controller) style widely used in many modern desktop and Web applications.
In an MVC architecture, we divide our work into three parts—the controller, which acts like a switchboard, invoking the appropriate model and view; the model, which contains the data and some of the logic; and the view, which displays information to the user. If you have ever built a database-backed site with PHP and Smarty templates or with Zope and its Page Templates or even with Java and JavaServer Pages (JSPs), you already are familiar with at least some of these ideas. Rails simply makes them more explicit with its prenamed directory structure.
Although it can't do much, we now can start our empty Rails application with:
cd ~/Rails/blog ruby script/server
This starts the WEBrick HTTP server on port 3000. To access this fairly empty Rails site, we point our browsers to an appropriate IP address or hostname. In my particular case, I started Rails on my test server, whose IP address is 192.168.2.3. I thus point my Web browser to https://192.168.2.3:3000/. And sure enough, there I see a “Welcome on board” message, indicating I have set up Rails correctly.
Now that we know how to see the default message, let's move toward a “Hello, world” program. In Rails, there are two basic ways to do this. We can create a controller that returns HTML to the user's browser, or we can create a view that does the same. Let's try it both ways, so that we can better understand the relationship between controllers and views.
If all we want to do is include a simple, static HTML document, we can do so in the public directory. In other words, the file blog/public/foo.html is available under WEBrick—started by executing blog/script/server—at the URL /foo.html.
Of course, we're interested in doing something a bit more interesting than serving static HTML documents. We can do that by creating a controller class and then defining a method within that class to produce a basic “Hello, world” message. Admittedly, this is a violation of the MVC separation that Rails tries to enforce, but as a simple indication of how things work, it seems like a good next step.
To generate a new controller class named MyBlog, we enter the blog directory and type:
ruby script/generate controller MyBlog
Each time we want to create a new component in our Rails application, we call upon script/generate to create a skeleton. We then can modify that skeleton to suit our specific needs. As always, Rails tells us what it is doing as it creates the files and directories:
exists app/controllers/ exists app/helpers/ create app/views/my_blog exists test/functional/ create app/controllers/my_blog_controller.rb create test/functional/my_blog_controller_test.rb create app/helpers/my_blog_helper.rb
Also notice how our controller class name, MyBlog, has been turned into various Ruby filenames, such as app/views/my_blog and app/helpers/my_blog_helper.rb. Create several more controller classes, and you should see that all of the names, like FooBar, are implemented in files with names like foo_bar. This is part of the Rails convention of keeping names consistent. This consistency makes it possible for Rails to take care of many items almost magically, especially—as we will see next month—when it comes to databases.
The controller that interests us is my_blog_controller.rb. If you open it up in an editor, you should see that it consists of two lines:
class MyBlogController < ApplicationController end
In other words, this file defines MyBlogController, a class that inherits from the ApplicationController class. As it stands, the definition is empty, which means that we have neither overridden any methods from the parent class nor written any new methods of our own. Let's change that, using the built-in render_text method to produce some output:
class MyBlogController < ApplicationController def hello_world render_text "Hello, world" end end
After adding this method definition, we can see its results by going to https://192.168.2.3:3000/MyBlog/hello_world.
Notice how the URL has changed: static items in the public directory, such as our file foo.html, sit just beneath the root URL, /. By contrast, our method hello_world is accessed by name, under the controller class that we generated. Also notice that we did not need to restart Rails in order to create and test this definition. As soon as a method is created or changed, it immediately is noticed and integrated into the current Rails system.
If we define an index method for our controller class, we can indicate what should be displayed by default:
class MyBlogController < ApplicationController def hello_world render_text "Hello, world" end def index render_text "I am the index!" end end
Of course, it's not that exciting to be able to product static text. Therefore, let's modify our index method such that it uses Ruby's built-in Time object to show the current date and time:
def index render_text "The time is now " + Time.now.to_s + "\n" end
And voil� As soon as we save this modification to disk, the default URL (https://192.168.2.3:3000/MyBlog/, on my computer) displays the time and date at which the request was made, as opposed to a never-changing “Hello, world” message.
Let's conclude this introduction to Rails by separating the controller from its view once again. In other words, we want to have the controller handle the logic and the view handle the HTML output. Once again, Rails allows us to do this easily by taking advantage of its naming conventions. For example, let us modify our index method again, this time removing its entire body:
def index end
This might seem strange at first glance. It tells Rails that the MyBlog controller class has an index method. But it doesn't generate any output. If you attempt to retrieve the same URL as before, Rails produces an error message indicating that it could not find an appropriate template.
Because the template is a view, we can define it inside of the blog/app/views directory of our application. And because we are defining the index view for the MyBlog class, we modify the index.rhtml file in the my_blog subdirectory of views. Notice how Rails turns ThisName into this_name when it comes to directories. Doing so saves users from having to think about capitalization in URLs, while staying consistent with traditional Ruby class naming conventions.
.rhtml files are a Ruby version of the same kind of template that you might have seen before. It acts similarly to ASP and JSP syntax, with <% %> blocks containing code and <%= %> blocks containing expressions that should be interpolated into the template. However, nothing stops us from creating an .rhtml template that actually is static:
<html> <head> <title> Hello, again! </title> </head> <body> <p>Hello, again!</p> </body> </html>
Consider what happens now if you attempt to load MyBlog in your browser. The controller class MyBlog is handed the request. Because no method was named explicitly, the index method is invoked. And because index doesn't produce any output, the my_blog/index.rhtml template is returned to the user.
Finally, let's take advantage of our template's dynamic properties to set a value in the controller and pass that along to the template. We modify our index method to read:
def index @now = Time.now.to_s end
Notice how we have used an @ character at the beginning of the variable @now. I found this to be a little confusing at first, as @ normally is used as a prefix for instance variables in Ruby. But it soon becomes fairly natural and logical after some time.
Finally, we modify our template such that it incorporates the string value contained in @now:
<html> <head> <title> Hello, world! </title> </head> <body> <p>Hello, world!</p> <p>It is now <%= @now %>.</p> </body> </html>
Once again, you can retrieve the page even without restarting Ruby. You should see the date and time as kept on the server, updated each time you refresh the page.
Ruby on Rails is, without a doubt, one of the most talked-about Web technologies to emerge in the past few years. This month, we saw how straightforward it is to create a new Rails application, to create a controller and a view and to integrate them using a combination of naming conventions and relatively standard template syntax. However, we did not discuss views, particularly those associated with a relational database. Next month, we will do exactly that, connecting Rails to the PostgreSQL database. I believe doing so will begin to show why people are so excited about Rails and why it might be a good tool for many Web developers to learn.
Resources for this article: /article/8457.