Rails 3 ActiveRecord queries - I'm missing something very BIG

Hi,

I know I am missing something very big regarding the changes with
respect to activerecord in Rails 3.

I can't find the explanation. And I'm sure someone will kick my ass for
not
finding the right piece of info in the docs and guides. Please do.

I have a working piece of code but I don't like it.

So. Very basic association:

class Project < ActiveRecord::Base
  has_many :tasks
end

class Task < ActiveRecord::Base
  belongs_to :project
end

The task table has the foreign key:
t.integer "project_id"

I can create a task this way, and the resulting task has the correct
project id stored

@project = Project.find(1)
@task = @project.tasks.build(params[:task])
@task.save

Now I get the project record using the Rails 2 way:

@project = Project.find(1) triggers:
Project Load (0.2ms) SELECT `projects`.* FROM `projects` WHERE
(`projects`.`id` = 1) LIMIT 1

@project.inspect outputs:
#<Project id: 1, name: "test", created_at: "2010-11-18 15:15:23",
updated_at: "2010-11-18 15:15:23">

@project.tasks.inspect shows:
[#<Task id: 1, title: "test", project_id: 1, created_at: "2010-11-18
15:20:06", updated_at: "2010-11-18 15:20:06">]

But now I want to use the Rails 3 way:

@proj = Project.where(:id => params[:id]) trigger:
Project Load (0.3ms) SELECT `projects`.* FROM `projects` WHERE
(`projects`.`id` = 1)

@proj.inspect shows:
[#<Project id: 1, name: "test", created_at: "2010-11-18 15:15:23",
updated_at: "2010-11-18 15:15:23">]

And @proj.tasks.inspect gives:
NoMethodError (undefined method `tasks' for
#<ActiveRecord::Relation:0x00000103922f30>):

Now, if I use:
@proj[0].tasks.inspect then I get the tasks for the project.

Is this the right way? I have the feeling it is not.

Cheers.

Hi,

I know I am missing something very big regarding the changes with
respect to activerecord in Rails 3.

I can't find the explanation. And I'm sure someone will kick my ass for
not
finding the right piece of info in the docs and guides. Please do.

I have a working piece of code but I don't like it.

So. Very basic association:

class Project < ActiveRecord::Base
has_many :tasks
end

class Task < ActiveRecord::Base
belongs_to :project
end

The task table has the foreign key:
t.integer "project_id"

I can create a task this way, and the resulting task has the correct
project id stored

@project = Project.find(1)
@task = @project.tasks.build(params[:task])
@task.save

Now I get the project record using the Rails 2 way:

@project = Project.find(1) triggers:
Project Load (0.2ms) SELECT `projects`.* FROM `projects` WHERE
(`projects`.`id` = 1) LIMIT 1

@project.inspect outputs:
#<Project id: 1, name: "test", created_at: "2010-11-18 15:15:23",
updated_at: "2010-11-18 15:15:23">

@project.tasks.inspect shows:
[#<Task id: 1, title: "test", project_id: 1, created_at: "2010-11-18
15:20:06", updated_at: "2010-11-18 15:20:06">]

But now I want to use the Rails 3 way:

@proj = Project.where(:id => params[:id]) trigger:
Project Load (0.3ms) SELECT `projects`.* FROM `projects` WHERE
(`projects`.`id` = 1)

@proj.inspect shows:
[#<Project id: 1, name: "test", created_at: "2010-11-18 15:15:23",
updated_at: "2010-11-18 15:15:23">]

where() is returning an array of objects. That's not technically accurate, but once you ask for the result of where() using all or inspect or anything else, it gets turned into an array.

There's nothing wrong with writing Project.find(params[:id]) for finding a specific instance...

Thanks Philip!

Yeah I wanted to include the tasks while getting the project.

I think this does it Rails 3 way:
@proj = Project.includes(:tasks).find_by_id(params[:id])

@proj.tasks returns the array of tasks and looks much better.

Cheers.

Just a note to point out that the .includes(:tasks) is not required.
@proj.tasks will still work without it (unless this has changed in
rails 3). Using includes will reduce the number of hits on the db
however.

Colin

Except that when loading a single record it's pretty pointless: a
second query is used to load the tasks, so there isn't much point of
doing it ahead of time (of course if you were loading 20 projects it
would be a different matter)

Fred

Frederick Cheung wrote in post #962548:

Just a note to point out that the .includes(:tasks) is not required.
@proj.tasks will still work without it (unless this has changed in
rails 3). Using includes will reduce the number of hits on the db
however.

Except that when loading a single record it's pretty pointless: a
second query is used to load the tasks, so there isn't much point of
doing it ahead of time (of course if you were loading 20 projects it
would be a different matter)

In other words, it sounds like (as in Rails 2) it's generally better to
use joins than includes.

Not to hijack the thread, but: what's the point of includes? Why make a
separate query when the DB could do it in one query with a join? I've
never understood this. What, if anything, am I missing?

Fred

Best,

Hi,

Thanks for the comments. Yeah :include would make only when handling
some amount of data to include. No much point if it is only a single
task.

I checked with Mr. Bates and got a lesson about all this. For Rails 2
but anyway the principle should be the same in Rails 3.

http://asciicasts.com/episodes/181-include-vs-joins

So as some of you pointed out joins is a better option in most of the
cases, since you can pretty much achieve the same and gain more control.

Regards.

However I think that in your example
@proj = Project.find_by_id(params[:id])
@tasks = @proj.tasks

neither is necessary. Joins will do nothing for you, includes will
provide a small efficiency improvement over not including.

Colin