What is the proper way to eager load associated objects for a 'has_many' association?
You should use includes method, like in following:
Article.includes(:comments).where(title: 'Sample text')
For your first case, you don't really need eager loading, since you only select one record, so this is not n+1 problem. You can just do:
article = Article.find(1)
article.comments
If you use include your articles frequently, you may define scope:
scope :with_comments, -> { includes(:comments }
and simply call it:
Article.with_comments.where(title: 'Sample text')
When your relation into which you want to include comments
comes from another association, nothing changes, you can do both:
@current_user.articles.includes(:comments)
and
@current_user.articles.with_comments
How does eager loading work? I mean I know what it 'does' but can I replicated it by doing a 'side' query?
Eager loading is doing something very similar to what you are doing, but in addition to simply querying the database, it's also establishing relationships. When you retrieve a model from the database that has related models, the related models are generally loaded on demand. The example from the guides is:
clients = Client.limit(10)
clients.each do |client|
puts client.address.postcode
end
When you do the first query, there's a call to the database to grab ten clients. As you iterate through them to get the postcode that is associated with a client address (which presumably lives in a different table), you'll need to do 10 more queries to grab the proper addresses. By using eager loading, you can do the whole thing in just two queries (which are handled under the covers).
clients = Client.includes(:address).limit(10)
This grabs the ten clients, then does another query (similar to yours) to grab the addresses that are in the array of client_id's. These are then resident in memory, with relationships in tact, so you don't need to make another database call to get them.
If you tried to replicate this by just loading them seperately:
clients = Client.limit(10)
addresses = Address.where("client_id in [my ID array]")
clients.each do |client|
puts client.address.postcode
end
You're still going to be hitting the database for each of the addresses, since those objects aren't associated with each other except through the database id's. The objects are loaded, but the relationships aren't created between them.
Trouble on eager loading and using the 'where' method
In case 1 the where clause only applies to categories. If you also want it to apply to comments you can do this:
article_categories =
article
.categories
.includes(:comments)
.where('categories.user_id = ? AND comments.user_id = ?', @current_user.id, @current_user.id)
How to eager load an association after eager loading on the parent?
I'm posting this an answer to make sure that it's clear it's been resolved. Once I'm capable I will accept this as the correct answer.
Baldrick's comment got me to thinking about how exactly I was filtering out activities for the user so that I only had the activities logged to the active organization. I was performing:
user.activities.where("organization_id = ?", org.id)
Which would force a query every time regardless of what I've done. So I changed it to:
user.activities.select { |o| o.id == org.id }
Which now performs what I've wanted (after @Baldrick's recommendation as well).
Lazy Loading vs Eager Loading
I think it is good to categorize relations like this
When to use eager loading
- In "one side" of one-to-many relations that you sure are used every where with main entity. like User property of an Article. Category property of a Product.
- Generally When relations are not too much and eager loading will be good practice to reduce further queries on server.
When to use lazy loading
- Almost on every "collection side" of one-to-many relations. like Articles of User or Products of a Category
- You exactly know that you will not need a property instantly.
Note: like Transcendent said there may be disposal problem with lazy loading.
Related Topics
Getting Only New Mail from an Imap Server
How to Save Values into a Yaml File
Preferred Ruby Plugin for Eclipse
Put Haml Tags Inside Link_To Helper
How to Get a Date from a Week Number
Prepend a Single Line to File with Ruby
Rails: Render View from Outside Controller
Getting Webpage Content with Ruby -- I'm Having Troubles
How to Set/Get Session Vars in a Rack App
Ruby on Rails: Devise, Want to Add Invite Code
When to Use a Lambda in Ruby on Rails
Rails 4 How to Ignore Pending Migrations
Extracting the Last N Characters from a Ruby String
How to Get the Latest Record from Each Group in Activerecord
Including a Ruby Class from a Separate File