ruby-on-railsruby-on-rails-4associationseager-loading

Rails fetch all including last row from association


I have two model with has_many belongs to relation.

Scheme has_many navs

I need to fetch all the Schemes with only last nav value. I have 10 Schemes and each scheme has around 100k navs but I need only last record which is the current value.

With eager loading will load all the navs

Scheme.all.includes(:navs)

How can I apply condition to to get only last row of nav for each schemes while eager loading.

UPDATE with Log

If I run

Scheme.includes(:current_nav).limit(3)

these are the queries executed by AR

SELECT  `schemes`.* FROM `schemes`  LIMIT 3
SELECT `navs`.* FROM `navs`  WHERE `navs`.`schemeCode` IN ('D04', 'D01', 'D30')  ORDER BY id DESC

How the second query works, it will take all the navs whose schemeCode falls under list and order those by id DESC , but how it will be associated with particular scheme exactly.


Solution

  • How about creating an another association like this:

    class Scheme < ActiveRecord::Base
      has_one :current_nav, -> { order('id DESC').limit(1) }, class_name: 'Nav'
    end
    

    Now you can:

    Schema.includes(:current_nav).all
    

    or:

    Schema.includes(:current_nav).last(10)
    

    will eager load only last nav of the queried schemes.

    Explanation: includes is one of the methods for retrieving objects from database in ActiveRecord. From the doc itself:

    Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method of the Model.find call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.

    And, since we have the association setup with current_nav, all we had to do is to use it with includes to eager load the data. Please read ActiveRecord querying doc for more information.