Using :include with has_one vs. has_many

While I’m happy to continue talking about the vagaries of Rails
deployments, I
also need to actually build apps. :slight_smile:

I may have discovered a bit of a problem with :include as it applies to
has_one
associations. First, let me say that I’m a big fan of :include for
reducing the
number of SQL calls. There are times when I wish it could go more than 1
step
away from the parent object, but I kind of understand why it can’t. Now,
on to
my “discovery”…

Completely contrived example follows:

I have the following Models:

class Author < ActiveRecord::Base
has_many :posts
end

class Post < ActiveRecord::Base
belongs_to :author
has_one :category
end

class Category < ActiveRecord::Base
belongs_to :post
end

There are many authors in the database that no posts, and there are
several
posts in the database that have no category.

If I do:

@authors = Author.find(:all, :include => :posts)

Every entry in the @authors array will have a posts list attached to it.
This
list will be empty if there are no posts for that author, which is great
for
handling associated posts in a view.

However, if I do:

@posts = Post.find(:all, :include => :category)

We actually see something different (and I think, inconsistent). Only
those post
objects that have an associated category will have a category entry in
their
hash. Those without, don’t have a category entry.

Sorry for the length… here’s my actual question. :slight_smile:

Why doesn’t :include result in an empty object in those posts without an
associated category record? If I loop over @posts and make a call to:

post.category.nil?

ActiveRecord ends up making additional SQL calls for every case where
that
statement evals to true. Why doesn’t the :include “work” for these
cases?

OK, so I really had 2 questions…

-Brian

Joshua S. wrote:

end
end

class Category < ActiveRecord::Base
has_many :posts
end

Nope… I typed exactly what I meant. But, remember, my example was
deliberately
contrived to show what I’m seeing. Yes, a category could have multiple
posts,
but in this case they don’t.

Also, I’m not looking for help in making “proper” associations (I’m
already
pretty good at data normalization ;). I’m trying to understand a
behavior I’m
seeing with has_one associations being used with :include vs. the
behavior of
has_many associations.

-Brian

I think you have your Category associations backwards. belongs_to goes
in the model with the foreign key.

class Author < ActiveRecord::Base
has_many :posts
end

class Post < ActiveRecord::Base
belongs_to :author
has_one :category
end

class Category < ActiveRecord::Base
belongs_to :post
end

A Category would have many posts, not belong to only one. Try this:

class Post < ActiveRecord::Base
belongs_to :author
belongs_to :category
end

class Category < ActiveRecord::Base
has_many :posts
end

–josh

Yep, as far as I can see through the code, if there is no
corresponding record in the database for a has_one association Rails
leaves this association uninitialized. Meaning that the first time you
try to access it, it’ll try to load it again.

Submit the request for improvement.

Kent

On 2/17/06, Brian V. Hughes [email protected] wrote:

has_one :category
belongs_to :category
Also, I’m not looking for help in making “proper” associations (I’m already
pretty good at data normalization ;). I’m trying to understand a behavior I’m
seeing with has_one associations being used with :include vs. the behavior of
has_many associations.

-Brian


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails


Kent