Scaling Complex Rails Applications

After ten years of development Rails is a mature framework, and a recurring theme at conferences is how to build and maintain Rails applications that are increasingly complex. Rails achieved early success as an opinionated framework that emphasizes MVC and convention over configuration, but as developers have tackled ever more ambitious projects there has been divergence as to how to structure them.

What is generally agreed is that business logic should reside in models, away from controllers, views and API implementations. This has led to ‘fat’ models and discussion of strategies to manage them such as this blog post from CodeClimate titled ‘7 Patterns to Refactor Fat ActiveRecord Models‘. An important point often missed when first learning Rails is that app/models is not intended exclusively for classes persisted with ActiveRecord as it may include other domain objects. In addition to domain objects other popular patterns used to structure code include form objects, presenters, decorators and service objects. Presenters and decorators intermediate between controllers and views, whereas service objects intermediate between controllers and models.

Presenters and decorators are probably less controversial in the Rails community and have done much to replace view helpers. Service objects, however, have been disparaged by DHH in favor of concerns, but many developers with a traditional OOP background are unconvinced by his approach. One example project that uses service objects is GitHub itself. More recently Collective Idea have published an ‘interactor’ gem that elaborates this approach.

These strategies all result in more classes, and probably the first step in managing a codebase with many classes is to introduce namespaces. The Rails class loader automatically searches sub-folders matching namespaces so source files can be arranged similarly to the namespace hierarchy. Given most developers nowadays navigate code using global search or ‘jump anywhere’ features in their text editor the neater project directory layout is of limited benefit, but namespacing can reduce name conflicts with libraries or between different areas of an application.

The next step beyond namespacing, suggested by Stephan Hagemann is to divide a project into internal engines or gems, an approach labelled Component Based Rails Architecture. An example project is provided at Each component has its own test suite so the scope of regression testing of any feature change is more limited. If a component proves reusable it can be split out from the original project altogether.

Beyond a component based architecture the final step to scaling a complex application is to break it apart into separate services interacting with an internal API, an approach referred to as Service Oriented Architecture (SOA). I will defer comment on the benefits and challenges of such an approach to a later post.

See also

Rails Development Resources

Wyncode recently blogged a “top 10” list of Rails development resources, what would be on my list?

Getting started on OS X with MRI Ruby you typically need to install Xcode command line tools, homebrew and rvm (with JewelryBox) or rbenv.  MRI Ruby (aka. CRuby, aka. yarv) is the de facto reference implementation written in C, though JRuby has gained a following in larger enterprises.  Microsoft at one time supported development of Iron Ruby for .NET but it has failed to gain much following.

Emerging in part as a reaction against the complexity of Java EE, the Rails community has tended to favor lightweight text editors such as TextMate, and now Sublime Text, over more heavyweight IDEs such as Eclipse and Netbeans, though JetBrain’s Rubymine has had some success.  Vim continues to be popular with rubyists, with projects like Hermes.

If you don’t want to setup and maintain a local development environment you can now simply rent an online environment from Cloud9 or  Other essential online tools include shared code repositories like GitHub and Bitbucket and bug tracking/project management tools such as Pivotal Tracker, Assembla or CodeBaseHQ.

One of the strengths of Rails is it’s excellent community maintained documentation, both guides and apidocs.  Another great API resource is

For online learning Code School and Rails for Zombies is a popular beginner resource, and Confreaks is great for catching up with conference presentations.  Ryan Bates stopped publishing RailsCasts a year ago but Avdi Grimm has stepped in with Ruby Tapas.

Finally, one of the most important ingredients of any programming ecosystem are the libraries: Ruby Toolbox is a great place for learning about available gems from Haml to Inherited Resource, from Nokogiri to Grape and ActiveAdmin.

I hope I’ve piqued your interest to look at any one of these.

Year four with Rails

Another year with Rails already.  The e-commerce project I’m leading has grown to 20kLOC with 1,400 tests maintained by an international team coordinated using Assembla.  The biggest addition to our toolbox has been Airbrake and its seemingly unrelenting production bug reports.  The other biggest challenge has been refactoring increasingly sophisticated factories to support the ever growing test suite.  Our infrastructure has changed significantly also in the face of continuing growth, but that’s another story.

A third year with Rails

This last year Ruby 2.0 has been released (Feb) and Rails 4.0 (Jun). I’ve embraced Sublime Text and git flow branching. Spork has been supplanted by Zeus. I’ve dabbled with OpenStruct, metaprogramming and AcitiveSupport::Concerns. New gems I’ve been learning include Enumerize, InheritedResources, Formtastic, Resque and Mechanize. I published a minor extension to the authorize-net gem and got hands on with CoffeeScript.

A second year with Rails

My second year with Rails has been increasingly team oriented, using online collaboration tools like GitHub, PivotalTracker, Atlassian BitBucket, CodeBaseHQ and Assembla.  Even though I was productive with Windows for a year on a one person project I’ve now joined my colleagues in using OS X with RVM.  My use of TDD has continued with adoption of Cucumber, RSpec, FactoryGirl and Spork, and for better or worse I am now using MySQL more than PostgreSQL.

The past year has seen the release of Ruby 1.9.3 (October) and Rails 3.1 (August) and 3.2 (January).  Ruby 1.8.7 has been scheduled for no further support after June 2013.

Testing ssl_requirement with pound

ssl_requirement is a Rails gem by DHH to declaratively redirect requests to SSL.  It is useful, for example, to ensure all access to a checkout page is secure.  SSL encryption, however, is usually handled by a webserver such as Nginx or Apache, and these are not typically used in Rails test mode.  It appears most developers simply disable SSL redirects during testing, but this allows certain defects such as correct handling of flash messages to go undetected.  To test SSL redirects I’ve started using a lightweight, secure reverse proxy called pound. The pound configuration file can be kept to a bare minimum to forward requests from port 8443 to 3000 and encrypt the response:

  Port    8443
  Cert    "pound.pem"
  AddHeader "X_FORWARDED_PROTO: https"
      Port    3000

To run pound:

pound -vf ./pound.conf

Rails development with multiple MySQL instances

Sometimes supporting multiple clients or projects can result in a need for more than one version of MySQL on the same workstation. This can be a pain, especially with the Ruby native mysql2 gem that can fail with a cryptic ‘failed to allocate memory’ when used with the wrong client libraries.

To address this I’ve started using Bitnami’s RubyStack.  Bitnami’s stacks provide a graphical installer that allows you to quickly specify a non-standard installation location and ports for your developer infrastructure so you can easily install the stack alongside the project being supported.

Instead of using RVM for development I now prepend the RubyStack to my path before working on the supported project:


Be aware the Bitnami stacks are 32-bit. The stacks include graphical and command line tools to start and stop components, see the Bitnami wiki components for more details. Bitnami AIMs are also available on EC2, various deployment options are discussed in the RubyStack README.

Installing Ruby Enterprise Edition on RHEL

RHEL5 is packaged with ruby 1.8.5 which is now outdated. To replace it with REE:

rpm -e `rpm -qa|grep ruby` # remove outdated ruby packages
sudo yum install wget -y
sudo yum install gcc-c++ make patch zlib-devel -y
sudo yum install openssl-devel readline-devel -y
cd /tmp
tar xzvf ruby-enterprise-1.8.7-2011.03.tar.gz
sudo ./ruby-enterprise-1.8.7-2011.03/installer --dont-install-useful-gems --auto=/opt/ruby-enterprise
cat > /etc/profile.d/ <<EOF
if ! echo ${PATH} | /bin/grep -q /opt/ruby-enterprise/bin ; then

. /etc/profile.d/

mysql gem installation on Windows x64

Having run into multiple issues setting up MySQL with Rails on Windows x64 my recommendations are:

  • Install the 32-bit version of MySQL, do not try to use the 64-bit version.
  • Install into a path with no spaces, do not accept a default like "C:\Program Files\MySQL\MySQL Server 5.5\"
  • Install the MySQL gem with an invocation similar to:
         gem install mysql -- --platform=ruby --with-mysql-dir="D:\Programs\MySQL\MySQL-Server-5.5" --with-libmysqllib="D:\Programs\MySQL\MySQL-Server-5.5\lib\"
  • Be sure to uninstall/reinstall whenever you install a new version of MySQL.
  • Make sure D:\Programs\MySQL\MySQL-Server-5.5\lib is included in your path, as well as D:\Programs\MySQL\MySQL-Server-5.5\bin. Make sure other copies of libmysql.dll are not being picked up from elsewhere on your path or your ruby installation directories.

Unfortunately with mysql-5.5.15-win32, mysql-2.8.1-x86-mingw32 and Windows 7 x64 even this was not enough: after experiencing a segmentation fault running rake db:create I gave up and downloaded the libMySql.ddl from InstantRails.

    One year with Rails

    One year since I picked up ‘Agile Web Development with Rails’ and coded my first Rails model/controller/view: seems so long ago now.

    Things I’ve mastered in the past year:

    • Test driven development using unit and functional tests.
    • Master-detail forms using Ajax to add and delete rows, fetching product details in JSON for codes entered into a line item.
    • Prototype and jQuery, including jQuery UI datepickers.
    • Loading and parsing XML data files using Nokogiri.
    • Building complex reports using nested views in PostgreSQL, maintained using rails_sql_views.
    • Creating formatted, multi-tab Excel spreadsheets using Spreadsheet gem.
    • Creating pixel-perfect PDF reports using JasperReports loaded using Java-Ruby bridge.
    • Hosting using Apache with Passenger, Mongrel, Thin and Unicorn.
    • Monitoring using ScoutApp.
    • Upgrading a production app from Rails 2.3.4 to Rails 3.0.9.
    • Switching from ERB to HAML.

    Posts navigation

    1 2 3 4 5 6
    Scroll to top