The Rails Way

Reviewed December 11th, 2007 @ 09:27AM

[Book Cover] The Rails Way

The Rails Way by Obie Fernandez is an extremely thorough book about Ruby on Rails. Addison-Wesley has another book that has always been by my side as a reference while programming Ruby: The Ruby Way. I love this book for its depth and attention to detail. Many times I wished there was a book that had the same depth and attention to detail, only focused on the Rails framework. That book is now here and hasn't left my desk for the past month. Obie Fernandez does an excellent job of walking you through the life-cycle of a Rails request, taking you into the guts to figure out how things work, and ultimately how you can extend it to fit your needs. The journey starts with looking at the available configuration options and takes us all the way through testing, deploying, and monitoring our application. With the recent release of Rails 2.0.1 - this book still stays relevant as Obie covers many of the new features and fixes in Rails 2, including ActiveResource. Lets take a look at some of the aspects covered.

  • The book starts off with your environments and configuration options. This encompasses everything you find within the /config folder. We dive into environment.rb and look line-by-line at each option, its purpose, and our available options. It is important to note that in Rails 2 they have extracted user configuration options into their own files stored in /initializers. This means that the environment file stays squeaky clean while still giving you options to extend.

    We then take a look at the default environments in the /environments folder. Each are discussed in detail, and more information is given on creating your own environments for different needs.

    The chapter rounds off discussing Rails log files, which are valuable no matter what you are doing. We inspect the default logging options and how to analyze some common bottlenecks.

  • Now it is time to move on and start working with controllers. This chapter starts off with an excellent quote and piece of advice: keep your business logic in the models. Fat models, skinny controllers. The controller is there to map requests between your data source and the views. We start off looking at the basics of dispatching and then move to the controller tasks. Controllers have a very important task of handling the requests and serving up the proper templates. We look at several different ways of rendering: the default actions template, another actions template, inline, text, and nothing, to name a few. We also look at rendering other data types all together. We also have another option, and that is to redirect. We get a nice list of HTTP status codes and how to properly redirect from our controllers, using the proper status code.

    Next we dive into managing the filter chain. Filters are used for many things in a controller, from authentication to security settings. Managing the filters and inheritance can help you to keep your code DRY. The chapter comes to a close with a discussion of streaming files, which is never an easy task due to browser quirks.

  • With an understanding of our controllers under our belt, we move to routing. Routing is the process of both recognition and generation. This means routing in Rails gives you great flexibility over your URL structure and managing your URLs within your application. We look at the basics of routing, how it is recognized, processed, and the order in which it executes. If you have only scratched the surface of routing in rails, you need to read this chapter. Rails has default routes and ways for us to access the params in our controller. Looking at your views, however, you can see the areas that could lead to repetitive code. Always re-stating your controller, action, and any extra parts. This could be wrapped in a helper, or you could use the power of routing in rails and create named routes. Named routes allow us to take advantage of generation. Instead of writing link_to 'Blog Entry', :controller => 'blogs', :action => 'show', :id => @entry we can simply write link_to 'Blog Entry', blog_entry_path(@blog). This comes from creating a route like map.blog_entry '/entry/:id', :controller => 'blogs', :action => 'show'. This is a very simple example, and this chapter walks through all other options such as requirements, with_options, and setting our custom params.

    The ability to manage your routes at a deeper level gives you much more flexibility within your application and helps to keep your view code clean of clutter. This chapter covers each and every detail of routing and how we can use it to our benefit.

  • There is an even easier way to manage your routes using a RESTful approach and Rails resources. This chapter is chock full of useful examples to help you make sense of REST and how it relates to your application. In a nutshell, Rails implements REST through routing and the proper use of appropriate HTTP verbs. Your CRUD actions are linked to each (GET and Read, Create and POST, Update and PUTS, and Destroy and DELETE). In order to benefit from RESTful resources, we need to stick to a few standards. First off, we need to create the routing resources with map.resources :books. You can have either singular or plural map.resource :session. Then we need to utilize the available methods in our controllers that correspond to our HTTP requests. These include: index, show, edit, new, create, update, and destroy. We also have the ability to serve up different content based on the HTTP request using the respond_to block. One resource could have many different representations: HTML, XML, and JSON to name a few. This means that we could have a request for /books.html and serve up the HTML, or /books.xml and serve up the resource as XML.

    You have full freedom and flexibility to extend your routes with an array of other options. You could have nested routes. You could control the name_prefix and path_prefix. With each of these, Rails gives us a handful of named routes to use within our application. Using the books example we are given: books_path, book_path, edit_book_path, new_book_path. The _path part creates URLs like /book/1, whereas we are also given _url, hash, and formatted that give us the full URL, formatted URL, and hash of the URL.. This chapter discusses each and every aspect of RESTful routing and Resources within our Rails application.

  • Find yourself still confused with the innards of routing? The next chapter reflects on routing and dives into the console to show you how routes work. Seeing this gives you a clearer picture of how you can take advantage of the routing in Rails. We are also introduced to a plugin which is now standard in Rails 2 that lets you type rake routes in the console and get a full list of all of your routes, what they expect, and how they are mapped. This is an indispensable tool as you start dealing with nested routes with extra resources.

  • Now we have a firm grasp of the request cycle and how to manage the requests. Now it is time to move to the beast that is ActiveRecord. ActiveRecord has so much depth that it gets 4 chapters devoted to the different aspects. We begin with the basics and using migrations to manage our database schema. Again, we explore each and every option for our columns, types, and mappings.

    Our tables have been created, time to look at our Models. We briefly look at setting our associations (more to come in the next chapter) and how Rails recognizes our associations and maps them to the corresponding database table. We look at how to do our basic CRUD and the many available options to extend your attributes and finder methods in your models. We get to see all of our options with our find and dynamic attribute based finder methods. These include :select, :conditions, :order, :group_by, :joins, and :limit to name a few.

    The nice part is that you are never locked into a specific way. ActiveRecord is very powerful and has security options such as bound parameters and protection from SQL injection out of the box. However, you never have to feel limited as you can also use find_by_sql and write your own SQL if you have the need. This chapter shows us how to use all available methods, our configuration options, and managing our connections.

  • One of the nice parts of Rails is the inclusion of proxy methods known as associations. These methods allow you to specify that a blog has_many :posts. In return we get access to our data through @blog.posts. This is a very simplistic example, and this chapter walks us through has_one, has_many, has_many :through, has_and_belongs_to_many, and belongs_to and discusses all of our available options to each. We look at how each is composed, how we can validate against our associations, and how we can control things through the chain of callbacks. This includes building, validating, and creating association objects. Lastly we look at using Association Extensions on our collections.

  • Keeping your data clean is an important part of any application. Now we move on to ActiveRecord validations to see exactly how we can keep our data clean. Just as with other chapters, we walk through all available methods and options for validation of our data. Rails has many validation methods built-in, but this chapter goes beyond those methods and shows us how to do custom validations on our attributes, when to do validation in the available callback methods, and how to deal with our returned errors.

  • While I wouldn't consider everything in the previous chapters to be basic, it is time we moved on to some advanced ActiveRecord. This chapter is focused on taking full advantage of the array of callback methods, creating and using observers, single-table inheritance, and polymorphic models. Each of these are discussed in great detail with usage examples of each. Callback methods allow us to manipulate and work with our data at different points in the request cycle. Things like before_save, after_save, before_create, after_create, before_destroy, and after_destroy. We have different options for defining methods and registering them, or using one-line blocks. We also have the ability to define classes and calling them to help us keep our code DRY between models. In this process, it may be necessary to halt execution of the callback chain, as is the case with validation and errors.

    Observers are just that. They are code that observe your models and call different code and different points in the callback chain. This works well for things such as sending emails and logging. For instance, you could setup an observer that looks for the creation of a user and then sends the user an e-mail with ActionMailer. You keep this code out of your controllers, and out of your models, but still gain the access to the model object. The work needed to register the observers on your models lies with your environment.rb where you specify which observers to use.

    STI allows us to extract our business logic in several aspects. The example given is a User model that also has a Guest and and Admin User. You can have Admin extend your base User class on and extend your models as necessary for each model. This section is all about setting up your models to handle this inheritance properly. Considerations are given for STI, including overriding defaults and dealing with associations.

    This chapter finishes up with discussion and configuration of Polymorphic models such as commentable and taggable, a review of class scope and context, and how to alter ActiveRecord models at runtime.

  • Now we move to our views and ActionView. This chapter starts off with an introduction to ERb and some formatting examples. Next we take a look at the Rails structure, organization, and naming for the views. Using variables is the most important part of the view, so we are introduced to how to use instance variables, as well as other variables made available to us by Rails. Just as with other aspects of our code, we want to keep our Views DRY. We look at best practices for managing your views, partials, and collections that make it easy for code re-use.

    The last part of this chapter discusses caching. Caching takes some thought and planning, no matter what the size of the application. We look at page caching, action caching, and fragment caching. Along with the discussions related to each - we then see how to expire our stale content using Sweepers. Sweepers are much like observers that can clean out our stale content on create, update, and destroy actions. Caching is a complex subject, as there are many little pieces that must be taken into consideration. This chapter discusses some of the gotchas, and several methods to help you manage your caching process.

  • Sometimes we have code in our views that needs to be extracted or have some logic applied. In order to keep logic out of the views, we use Helpers. This chapter walks through each and every available helper and all of their configuration options with full examples of their usage. After dissecting all of our available helper methods, we are introduced to several ways of developing our own helpers and making them available in our views.

  • What would Rails 2.0 be without Web 2.0. Our next chapter dives into Ajax on Rails. The chapter starts off with some debugging tools to help us in the process, and an introduction to Prototype and Scriptaculous, the default JavaScript libraries. I must say that this chapter was the least inspiring, not to the fault of Obie or of JavaScript, but because of the way Rails embeds JavaScript inline with your HTML. We spend so much time talking about keeping our code DRY, and then we litter our markup with inline JavaScript that could easily be abstracted to an external file accessed via the DOM. My qualms aside, this chapter is much like the chapter related to Helpers. The beginning was spent explaining the available Prototype methods, then on to how they are used in the context of our application and the available Rails helpers for generating JavaScript. Several examples are given: Drag and Drop, Sortable, Autocompleter, and In Place Editors. We even have the ability to use RJS templates that allow us to write JavaScript with Ruby code. While this chapter is very exhaustive, I still believe there are better ways to manage your JavaScript.

  • Keeping state is an important part of any application. We now dive into session management. We look at how session management is implemented and the different storage mechanisms available to us. Other topics discussed were security and the usage of cookies. Session management will come in handy as we move on to discuss login and authentication.

  • The login and authentication chapter is devoted to the Acts as Authenticated plugin written by Rick Olson. Due to the different needs of applications, authentication and authorization are best left to the developer to implement. Acts as authenticated is a drop in solution to manage your authentication. The plugin creates several helper methods for us, and this chapter walks through each piece of the plugin to help us understand what is going on under the hood.

  • The ability of rails to handle different resources brings us to the chapter focused on XML and ActiveResource. This chapter starts off breaking down the to_xml method and all of the available options to extend and build it to your needs. This comes in handy when using the respond_to block to serve up different representations of your content. The second part of the chapter focuses on ActiveResource, the Rails 2 replacement for ActionWebService. ActiveResource shares many of the methods with ActiveRecord, so by this point things are looking very familiar. Just as with ActiveRecord, we examine all of our options with examples of each.

  • Another part of an application is the process of creating and sending emails as well as receiving them. This chapter is devoted to ActionMailer. We start off looking at our configuration options. After that, we explore each of the available methods. This chapter discusses sending plain text emails, HTML emails, multipart emails, and handling attachments. Once we create our ActionMailer methods, we are given instructions on how to actually send the emails. The last part of this chapter discusses receiving emails and reading incoming email messages using the Tmail API.

  • With so many pieces of our application in place, we now look at the methods of Testing. Rails embeds testing at the core and encourages it every step of the way. It isn't just there in case you need it, it is fully functional and there to help you write tests for each and every part of your application. This chapter walks through setting up your own tests, fixtures, and checking for errors. We see our configuration options and how rails organizes the tests within the application. We see how the tests are connected to the application and how we can use the many available methods to create our tests. With our tests in place we can run them and examine the returned results. Having this in place assures that as we develop our application our code still responds as we expect. We can develop and then run our rake tasks and make sure everything still works as expected.

  • Obie states:

    RSpec is a Ruby domain-specific language for specifying the desired behavior of a Ruby application

    This chapter discusses RSpec on Rails as a replacement for the default rails testing mechanisms. This chapter is exhaustive and dissects all available options for writing, maintaining, and running your tests. There are also details for installing it as a plugin to Rails and use this versus the default Test::Unit. This is one chapter I need to re-visit as it covers each aspect in great detail, and I don't have any experience with it (I know, shame on me).

  • We looked earlier at the acts_as_authenticated plugin, now it is time to look more into utilizing Plugins. The beautiful thing about Rails is that it has a solid core but gives developers the freedom to extend and build to their needs. Plugins are just that. They are subsets of code that you can install and use within your application. Rails has an excellent plugin system built in and makes it really easy to install and build your own. By using script/plugin you have many options available to you for managing your plugins. This chapter shows us how to discover, install, configure, and build our own plugins. It also shows us how to manage plugins with SVN and Piston.

  • We are finally nearing the end of our Rails application and it is time to discuss Production Configurations. We start off by looking at our production stack. The Web Tier, Application Tier, Database Tier, Monitoring, and Version Control are all discussed. The rest of the chapter provides configuration examples and init scripts for mongrel_cluster, nginx, and monit. The chapter rounds off with considerations for redundancy and fail-over, caching, performance and scalability, maintenance, and security.

  • Capistrano is a tool to help you streamline your deployment process. This chapter provides us with some Capistrano recipes as well as breaks down configuring and modifying Capistrano to fit your deployment needs.

  • 22 chapters later and we end with a topic related to Background Processing. An opening quote states: Waiting for Background processing allows us to extract resource intensive tasks into the background while allowing our Rails application to continue to respond in a normal fashion. This is useful for application pieces that need to handle large uploads or some sort of API authentication in the background, such as Credit Cards. This chapter presents us with our available options with some example usage scripts.

Whew, it has been a long journey. The details are important when you are building an application, no matter what the user base. Rails is a very powerful framework and provides us with many built-in features that handle some of the mundane tasks. It also gives us the flexibility to extend tasks to fit the needs of our application. The Rails Way teaches us just that: the rails way of planning, organizing, extending, and maintaining our applications while keeping our code as lean as possible. While we have the Rails API available to use (Which this book also provides the entire ActiveSupport API as an appendix), this book helps to clarify some of the muddy details. Obie highlights the clarification process with his excellent code examples and explanations.

It is hard to give a 22 chapter, 830 page book, full justice in a simple review. While working with Rails I always have a tab open with the API. Still, some of the examples could use some more examples or clarification. Obie gives that clarification in this book. He does an excellent job of staying on course, while also giving you a vast amount of resources for more research. Aside from the Pragmatic Programmers books I have had a hard time finding good, quality, Rails books. There are a few that walk you through simple application examples (much like the create a blog in 15 minutes example), but none that dive in as deep as this book. No matter what your skill level with Ruby on Rails, this book is a must have guide, reference, and resource. This is the definitive guide to Ruby on Rails.