Rails 3 lazy-loading and the console

While debugging an Rails 3 application in development, I started to wonder if the lazy-loading feature of ActiveRecord 3 was really working.

In a model, I was building a query depending on some parameters. Something like this (obviously simplified) :

class Thing < ActiveRecord::Base
  def initialize(what, options = {})
    collection = what.scoped
    collection = collection.limit(options[:limit] if options[:limit]
    [...]
  end
end

A great thing about Rails is the console. You start you application in a terminal and you can use it (except for controllers and view).

So I did a simple :

$ t = Thing.new(AnotherModel)

Then in my development.log file I saw a beautiful

SELECT * FROM things

The thing is until you really ask for the data, the database should not be queried and the object is a Relation, not a collection of your model.
In the documentation, I was reading that « asking for the data » is calling a method like « first », « last », « all » or any iterator. I didn’t use that kind of methods, it shouldn’t query the database.

I turned everything upside down, tried to look in ActiveRecord‘s code, then ActiveRelation‘s, then built a dummy application to see if my setup configuration was wrong, then read 2 times every article I could find about ActiveRecord Query Interface 3.0, then look in the Rails Lighthouse, then ask on several IRC channels, … nothing !
I started to question the reality of this « lazy-loading » feature.

Then I asked on Twitter and my friend Sébastien Gruhier (of the Maptimize fame) gave me the solution. It’s as simple as print, really !
The damn print IRB (the console) is using to show me the data I (in fact) asked for.

Here is the solution for the console :

$ t = Thing.new(AnotherModel); nil
nil
$ t.class
ActiveRecord::Relation < Object

I was able to verify that everything was working in the Controller/View part by clearing the whole view and still loading the page : no SELECT in the logs.

I admit that the few hours I spent on this scared me a little. Such a big bug on the Rails side could not be possible, but I used all the tricks I knew to find the issue. As often, an (great) outsider found the solution in a couple of minutes. I should have asked earlier. Even after a decade in this, I still make the mistake.

Cet article, publié dans Informatique, est tagué , , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s