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 then I get the tasks for the project.
Adding [0]

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

Cheers.

On Nov 18, 2010, at 1:13 PM, comopasta Gr wrote:

@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(params[:id])

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

Cheers.

On 18 November 2010 22:24, comopasta Gr [email protected] wrote:

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.

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

On Nov 19, 8:57am, Colin L. [email protected] wrote:

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)

Fred

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.

I won’t be able to resume the railscast accurately so I recomend to
check it out, for those who need it.

Regards.

Frederick C. wrote in post #962548:

On Nov 19, 8:57am, Colin L. [email protected] wrote:

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,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Sent from my iPhone

On 19 November 2010 14:45, comopasta Gr [email protected] wrote:

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.

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