Archive for the ‘Rails’ Category
Specialist: A pattern for carving up fat ActiveRecord models
All roads to a well-factored Rails application lead from fat controllers through fat models. Where to head next is less well mapped. Many patterns move non-model code into separate layers. When you’ve gone down that path as far as you can, your models can still be weighed down with code that would belong in a model — if there weren’t so much of it. Specialist is a pattern that makes it surprisingly easy to slice up your fat models into lean modules.
Using and testing automatic accessors and virtual attributes of ActiveRecord models
An ordinary ActiveRecord model object has an attribute for each column in its table. Each attribute has a reader method and a writer method. However, ActiveRecord also defines accessors on the fly to hold non-column query results. Also, sometimes it’s useful to define a new attribute, one not corresponding to a column or even to a field in a query result. These different kinds of extra attributes can interfere with one another, making them tricky to use and test. The best defense is to understand all of them well before using any of them. Let’s have a look.
What I did on my working vacation, 2016 edition
Indiegogo’s long-lived Rails application used many gems, causing issues in development and deployment. I wrote a couple of posts on Indiegogo’s engineering blog about solving those issues:
Also, I helped my colleague Mike Luby with How we get coverage on parallelized test builds.
Controlling database usage in RSpec and factory_girl, part 2: association strategy and unstubbed queries
An important part of testing a Rails application is establishing the correct relationship between the specs of each layer and the database. To correctly test the layer that they test, some types of specs (model and feature specs) should run against the database; other types should not. As well as ensuring correctness, policing database usage optimizes performance: tests that use the database are slower.
This post, part 2 in a two-part series, describes two measures that you can take to minimize incorrect and unnecessary database usage in RSpec specs that use factory_girl.
Controlling database usage in RSpec and factory_girl, part 1: Choosing and allowing appropriate strategies
When testing each layer of a Rails application, it’s important to create test model instances in the right way for that layer. Some specs need model instances that have been saved in the database, or that appear to have been; others need instances that have not. It’s also important to not use the database when you don’t have to, because every use makes your tests take a little bit longer.
This post, part 1 in a two-part series, lays out the appropriate use of factory_girl in specs of each layer of Rails, and gives a way to enforce that usage.
Upgrading GWW from Ruby 1.8.7 to Ruby 1.9.2 and RVM
Having already upgraded GWW from Rails 1 to Rails 2 and then Rails 3, the last step to bring it fully up to date was to upgrade to Ruby 1.9.2. It wasn’t difficult, but it took enough puzzling out to be worth writing down, and I even found a regression in Ruby.
Succinct specs for Rails named routes
I like all of my routes tested, and I like all of my routes named, and I like all of my named routes tested. I even like to test my RESTful routes; even though it feels a bit like testing Rails, it more than paid for itself when migrating to Rails 3. How, then, to spec a named route succinctly?
Rails’ named routes considered helpful
The current Rails best practice is to use RESTful routes. One nice thing about a RESTful route is that it comes with a name. Similarly, :member and :collection routes are automatically named. But sometimes you need a plain old arbitrary route, which you can then name or not as you wish. It may seem like overkill to give every route a name, especially if the route is referred to infrequently in templates. But there’s another place where you’re virtually guaranteed to need that named route again: in tests.
Avoiding extra queries in ActiveRecord 3
ActiveRecord 3 introduces a new query interface based on Arel. The new query methods are more succinct than the old :conditions
etc. syntax, and they’re easier to combine into complex queries. Scopes (formerly known as named scopes) are still present and useful, but there’s much less difference between a scope and a simple method that returns a query than there was before. Along with these carrots encouraging you to rewrite all your queries there is the stick of deprecation of the old syntax in Rails 3.1 and removal in Rails 3.2, so most people migrate to the new interface when they migrate to Rails 3.
Migrating GWW to the new interface went smoothly, but when I was reviewing some pages for performance recently I noticed ActiveRecord issuing some extra queries that I didn’t expect, and that weren’t necessary. Fortunately, once noticed, they were easy to eliminate.
Upgrading GWW from Rails 2, RSpec 1 and prototype to Rails 3, RSpec 2 and jQuery
GWW originated on Rails 1; I upgraded it to Rails 2 last year. I’d been putting off the upgrade to Rails 3 until a bug in Phusion Passenger which breaks redirects in Apache httpd was fixed, but I want to use a database adapter which supports MySQL spatial features, and that requires Rails 3. I said goodbye to page caching until (crossing fingers) Passenger 3.0.6, made a branch and started editing my Gemfile.
Although Rails 3 has been released for more than half a year, upgrading involved many hiccups and a couple of landslides. I’d have been happy to just update my gems and be done with it, but I had to hunt around enough that it seemed worth logging what I did in case it helped someone else. I’ve kept it as short and to-the-point as I could. Although I fixed all of the deprecations that Rails 3 reported as I encountered them, I won’t mention them further, since in every case they were completely clear and fixing them only required following instructions. I’ve also left out a handful of odd little incorrectnesses in GWW which worked in Rails 2 but broke in Rails 3, since the details probably won’t interest anyone else and the fixes were obvious. Otherwise, here’s how the upgrade went.