posted
Friday, September 7, 2007
by
topfunky
During a brief 2 years of writing Rails applications, I’ve learned many things that have become part of my normal workflow.
I recently published a draft of the first PeepCode PDF minibook. It’s called Ruby on Rails Code Review.

It currently contains 16 chapters of tips for building a solid Rails application and I thought it would be useful to briefly mention them here (I’ll be adding one or two more chapters for the final release). They are written as combinations of common mistakes and better implementations. If you like the term, you could call them “Best Practices.”
Are you doing these things in your applications? What would you add to this list?
Full Chapters
- Store sessions in the database (or at least not on disk, which is the default).
- Use a custom configuration file for passwords and API keys instead of storing them in your Subversion repository. I use YAML and mirror the style of database.yml.
- Use constants where needed. Instead of repeating strings like the address of your customer service reply email, set it once in a constant (in environment.rb or the appropriate environment file) and use that throughout your application.
- Keep time in UTC. A no brainer, and easy to do.
- Don’t loop through ActiveRecord models inside other models. Use eager loading if you need to work with multiple associated models. Better yet, write a custom SQL query and let the database do the work for you.
- Beware of binary fields. By default, all fields are returned with queries, including the full contents of any binary fields. Use
:select to pull out only the fields you need.
- Write tables to cache data for reports that span months and years. It’s much faster than re-generating a year’s worth of reports every time a page is loaded.
- Create a table with a list of country names. By default, Rails uses strings for selects and lists of countries, which doesn’t work well for reporting or database consistency between models.
- Avoid bloated controllers. Instead of piling actions into a controller, limit yourself to 10 actions per controller, then rethink your design.
- Keep your controllers and views skinny. In general, most of your code should be in your models, not your controllers or views.
- Don’t store objects in the session. Use integers or short strings if necessary, then pull the appropriate object out of the database for the duration of a single request.
- Avoid heavy response processing. Can you mark a record as needing to be processed, then use a cron job or a messaging server to do the long-running work? BackgroundRB is also an option. (I use this technique for filtering SPAM comments on this blog).
- Use ar_mailer to queue bulk emails instead of sending them during the Rails response cycle.
- Monitor your servers with the exception_notification plugin, munin, monit, or other tools.
- Don’t cut costs on hardware. You’ll quickly lose the money you thought you were saving if your developers have to spend even one day a month on unexpected server maintenance due to poor backups or cheap hardware.
- Test-drive your development.
Mentioned in Passing
- Use database indexes to speed up queries. Rails only indexes primary keys, so you’ll have to find the spots that need more attention.
- Profile your code. The ruby-prof gem and plugin helped me make an application three times faster with only minimal changes to the code.
- Minimize graphic-related dependencies. If your application only needs to make a few thumbnails, don’t waste memory by importing large graphics libraries. Look at mini-magick or image_science for lightweight thumbnailing.
- Avoid excessive repeated rendering of small partials.
- Use CSS instead of inline tags to apply selective styling.
- Don’t use ActiveRecord’s
serialize option to store large objects in database fields.
- Use
attr_protected :fieldname in models to keep database fields from being manipulated from forms (or from any calls to Model.update_attributes(params[:model])).
- Use Ruby classes and inheritance to refactor repeated controller code.
- Use unobtrusive Javascripting techniques to separate behavior from markup.
- Package self-sufficient classes and modules as plugins or RubyGems.
- Cache frequently accessed data and rendered content where possible.
- Write custom Test::Unit assertions or rSpec matchers to help with debugging test suite errors.
- Rotate the Rails and Mongrel logfiles using the
logrotate daemon on Linux.
- Build a reliable backup system.
- Automate deployment and maintenance with Capistrano or Vlad.
- Keep method bodies short. If a method is more than 10 lines long, it’s time to break it down and refactor.
- Run flog to determine overly complex methods and clases.
- Don’t use too many conditionals. Take advantage of
case statements and Ruby objects to filter instead of multiply-nested if statements.
- Don’t be too clever. Ruby has great metaprogramming features, but they are easy to overuse (such as
eval and method_missing).
- Become familiar with the most popular plugins. Instead of re-implementing the wheel, save yourself some time by using well tested, popular plugins.
(Thanks to Courtenay Gasking for many of these guidelines).
Several people have written to say that they have put together blank Rails projects that include all the plugins and defaults that they use on new projects. Maybe I should put one together that uses all the suggestions you see here?
In Other News
Over a year and a half ago, I signed on to write two chapters in a book about Rails Deployment. That book is now available for pre-purchase as a Pragmatic Beta PDF!
I’ll be speaking at RailsConf in Berlin! I’m up against Twitter, JRuby, and Amazon, but I doubt any of them will be giving away random PeepCode t-shirts, PeepCode coupons, or have their own marching band.
And there are a few hours left in the PeepCode one-year anniversary sale! Buy a 10-pack and get 12 credits instead of 10!
Leave a response
One that I don’t think many people use (in your login or user controller):
filter_parameter_logging :password, :password_confirmationOtherwise your logs will be filled with all your users passwords!
I would think that a mechanism that lets you view logs easily would be valuable. Perhaps the combination of syslog-ng + email + analyzer software + log rolling would be a good one.
Also, nagios for monitoring is invaluable for me.
I already used a token on the minibook draft and I think its brilliant. I’ve already implemented 4 or 5 of the recommendations in my current (first) project.
Where you mention
attr_protected, I’d sayattr_accessible. See SomethingLearned for the arguments that convinced me.i am also trying to learn more about ruby on rails.
these development tips will definately help me.
thanks you.
Thank you for bringing this knowledge together. As a Rails beginner it is priceless.
I really need to learn Ruby on Rails… it is powerfull!
Geoffrey, your posts always rock and these are some great tips.
Just as I have found your screencasts unlock doors, the info on this page has great value. After nearly a year and half developing Rails apps, I can honestly say Rails and Ruby have changed my life in a big way. And Geoffrey, your very reasonably priced knowledge sharing has helped immensely. Kudos.
Please, can everyone that wants to learn RoR, first learn AND understand the basics of ruby?
People continually come and ask how to do the most basic stuff and then complain that on #ror channel noone answers this. So please please please everyone encourage them to get the basics first, to learn walking before running first.
The entire thing could be compressed to just one tip: “Learn some basic programming before starting write code in Ruby on Rails”.
Why not making it open souce?
@Eugueny: The fact is that many people start learning basic programming every day, and some of those people start by learning Ruby on Rails.
If you’re already familiar with these tips, that’s great. For other people, I hope this will start them off on the right track to building solid applications.
really helpful, thanks!
i am trying to learn about ruby on rails.
these development tips will definitely help me.
thank you
When we try to address the question if this can be used for product development, it certainly can be, and is ideally suited for database driven web-based products. Rails is ideally suited for those who want to quickly deploy their web-based products; low cost internal prototypes and pilot applications; highly targeted internal applications and utility programs; and web 2.0 applications. One can assume that the smaller the development team and more ambitious the project, the more likely you are to benefit from Rails. Very small projects probably does not require Rails and can do with CGI programs and PHP, but when there is a use of relational database with more than one table, you are likely to benefit from Rails.
Thanks for posting this for the rest of us!