Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: `includes` a `has_many` relation with `limit`

I'm using Rails 4.2. I have 3 tables like this:

class Collection < ActiveRecord::Base
    has_many :shares
    has_many :images, through: :shares
    has_many :latest_images, -> { order(created_at: :desc).limit(10) }, class_name: 'Image', through: :shares, source: :image
end

class Share < ActiveRecord::Base
    belongs_to :image
    belongs_to :collection
end

class Image < ActiveRecord::Base
    has_many :shares
    has_many :collections, through: :shares
end

My goal is to select some collections and preload the first 10 newest cards of each collection using the latest_images relation.

If I do simply:

collections = Collection.where(some_condition).includes(:latest_images)

The problem is latest_images will contain all cards, not only the last 10 (even if there's a limit(10))

collections.first.latest_images.count # => more than 10!!!

Instead, if I add the limit(10) after loading the collections, I'll have a N+1 query problem:

collections.each { |collection| collection.latest_images.limit(10).do_something } # N+1 QUERY

Any solution?

like image 520
ProGM Avatar asked Oct 16 '15 15:10

ProGM


People also ask

How to avoid n 1 queries in rails?

You can avoid most n+1 queries in rails by simply eager loading associations. Eager loading allows you to load all of your associations (parent and children) once instead of n+1 times (which often happens with lazy loading, rails' default). As seen above, . includes allows nested association eager loading!

What is the difference between Has_one and Belongs_to?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

What is n 1 query in rails?

The n+1 query problem is one of the most common scalability bottlenecks. It involves fetching a list of resources from a database that includes other associated resources within them. This means that we might have to query for the associated resources separately.

What is dependent destroy in rails?

what is dependent :destroy. Dependent is an option of Rails collection association declaration to cascade the delete action. The :destroy is to cause the associated object to also be destroyed when its owner is destroyed.


1 Answers

There is a note tucked away in the associations documentation under "Eager loading of associations":

If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects.

So, it is behaving as documented even though that might not be the intuitive behaviour.

The work around is to not eager load the limited associated and to access separately afterwards. As you point out that's not ideal but it is almost certainly preferable to loading all of the associated objects without a limit.

like image 182
Shadwell Avatar answered Oct 26 '22 15:10

Shadwell