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