05 MarActiveRecord.find_by with join from irb

Friday, 05 March 2010 — 09:00

If you like to run your code on irb before it goes to the project like me, you might find this problem when running “find_by” ActiveRecord’s queries joining multiple tables.

Let’s take this as an initial example of what i mean:

projects = Projects.find(:all,
:select => "projects.id, projects.title, projects.version, managers.name",
:joins => :manager,
:conditions => "projects.technology='Rails'",
:order => "managers.name asc")

What would you expect from this?. I would expect a resultset with the values under :selected clause, that is an array of projects, with title, version and manager name.

However, if you run this from irb, you will get something like this:

[#<Project id: 18004351, title: "ggomeze.com", version: "1.0">]

Where is the manager’s name?. But if you run next command, in the worst case, you will get:

>> projects[0].name
=> nil

Let me explain you what might be happening here: you probably has an instance method in project class with same name!!. Really?, ok, let’s check it::

>>Project.instance_methods.grep(/name/)
["name","name_xxx"]

There you go!. So applying rule of thumb “right and top”, rails is running that method instead of getting the attribute from the resultset. That’s obviously a flag that we are not doing things right. There are several techniques to refactor that code. Delegates might be one.

Just to demonstrate manager’s name is there, let’s make a small change in our initial code:

projects = Projects.find(:all,
:select => "projects.id, projects.title, projects.version, managers.name as foo",
:joins => :manager,
:conditions => "projects.technology='Rails'",
:order => "managers.name asc")

And now, back to irb:

[#<Project id: 18004351, title: "ggomeze.com", version: "1.0">]
>> projects[0].foo
=> "Gerardo Gomez"

Don’t be lazy and refactor your models!

Ger

Comentarios

Añade tu comentario




(textile avilitado)
Negrita: *Google*
Enlace: "google.com":http://www.google.com
Imagen: !http://vicentgozalbes.com/images/avatar.png!

ó Cancelar