Tuesday, December 16, 2008

Beginning a Rails app -- for beginners

After some trial and error, I got my first significant Ruby on Rails application off the ground. By significant, I mean a dozen related tables, about 20 controllers, and some tricky business logic. I had been exploring Rails for a while and created a few toy applications, but hammering this one out still presented a challenge.

If you are used to programming CGI, PHP, or any application not built on a Model-View-Controller (MVC) framework, the learning curve is steep. While I can't offer up best practices -- I still have too much to learn -- I can offer up how-the-hell-do-I-get-started practices. For my own benefit, I created a list of steps to ease the pain of getting started.

Don't start here

As I mentioned, unless you are coming from another MVC framework, the learning curve is kind of steep. Rails has lots of nooks and crannies, lots of helpers and shortcuts that are not obvious at first. So, even though this is a beginning Rails article, it is not a good place to start learning about Rails. I suggest starting with a good book.

The three books I always have at hand when working in Rails are:

  • Programming Ruby: The Pragmatic Programmers' Guide (pickaxe)
  • Agile Web Development with Rails
  • Rails Cookbook

Also, I spent no time telling you how to install or set up Rails on your system. There are many places to find such information, and if you are running a Mac, you already have Rails installed, though you may need to set up your database.

Four terminals at Rails central

I do my text editing with vim (and sometimes nano), performing all work in the Terminal. Textmate and other GUI editors are popular but I prefer to stay in the Terminal. I have found that 4 terminal windows (or tabs) is ideal for working on a Rails application. That's 4 terminals for each Rails application, so if I was going to work on two at the same time, (unlikely), I would open 8.

I keep the Terminals ordered left to right and dedicate the first to working on Models, the next one for Views, the next one for Controllers, and the fourth one for performing other tasks such as debugging, reviewing logs, running scripts, etc. Keeping them in MVC order helps me stay organized while working and lets me switch between related views and controllers quickly.

Of course, I also have a browser window open to test changes as I go.

Start here

Keep in mind, these are not rules, just basic guidelines that can help you approach a new project.

  1. create the app structure with "rails appname", this command generates the directory structure for the application and all the configuration files
  2. create the database and tables (outside of rails), this is not the "rails" way, using migrations, but I prefer to do create/modify my database outside of rails
  3. configure /config/database.yml with database details
  4. create models, one per database table in app/models/
  5. add validate helpers and validate methods to models in app/models/
  6. create initial controllers/views using scaffolding with "ruby script/generate scaffold Model-name"; run once for each table/model using the singular form of the table name for the controller. (The model name is capitalized and singular).
  7. add business logic to a controller and set instance variables with data that will be needed in the view
  8. customize the default template in /app/views/layouts/. Layouts are used to hold common HTML and embedded ruby such as headers and footers for your pages. Usually, there is one layout per controller.
  9. fill in the views (often rhtml files), one for each method in the controller. Views and layouts control the presentation.
  10. repeat each step above starting with step 6 (the scaffolding step) for each table/model in your application, you can come back and add or change models later
  11. create new controllers not related to any models with "ruby script/generate controller Controller-name" and add methods and views as needed
  12. edit config/routes.rb to set the default URL for the application, rename public/index.html to index.html.old,
    e.g. map.connect '', :controller => "main", :action => "list"
    it must be the first map in the routes file.

For pure data entry forms, create an empty controller method with a corresponding view. The view will contain the form and call a different method to accept the data and display the results (in yet another view).

If authentication is needed, use a "before_filter" at the top of each controller to handle logins and set session data.

In Rails version prior to 2.0, the scaffold script generates non-RESTful code, while in 2.0 and later, it generates RESTful code. This is a concern if you were used to the way Rails worked before 2.0. I am not sure RESTful is really better, but either way it can be confusing if you upgrade to Rails 2.0 in the middle of developing an application and find that scaffolding no longer works the same way.

Rails is flexible

One of nice things about Rails is that it is flexible. You can use Rails helpers when constructing your views and web forms, or you can code them using standard HTML. If I was not comfortable using a particular form helper or could not get the syntax just right, I fell back to coding it in regular HTML. Rails had no problems merging form helpers and regular HTML in the same form within a view. In many parts of Rails, it is not all or nothing. You can use all, some, or none of the shortcuts.

The ease of modifying applications is another strength of Rails. It is relatively easy to add new functionality, tables, or features. You don't have to figure out everything before you start. It is also easy to rewire your application if you don't like the way it flows between screens or the way the pages are linked together.

Testing

I think the official best practice to test a Rails app is to write test scripts that assert conditions and report problems found. I haven't used test scripts yet, my skills are not advanced enough. Up to now, I have relied on three other techniques.

The first is using the "script/debugger" to stop my application at certain points so I can display the values of objects and variables. I think the script/debugger was either removed or replaced in Rails 2.0.

The quick and dirty way to test is to write data to :flash and view the contents of variables that way. The flash is a built in hash, part of the session data, used to display informational or error messages to the user. It is an easy way to debug simple problems.

For deeper problems, I write data to the log file using the logger object. It takes a little time to sift through all the stuff in the development log file, but you can see trends and what is passing through the application before and after the trouble spot.

Railsbrain

Finally, I want to point out an extremely useful reference web site for working with Rails: Railsbrain. It has an Ajaxy API reference for multiple versions of Rails along with syntax and sample code.

I expect to come back to this article in six months and laugh at the inefficiency of the way I started doing Rails, but for now, it was enough to get that first useful application done.