Argus9
Argus9

Reputation: 1955

ActiveRecord custom has_many association makes multiple calls to the database

I have a pair of ActiveRecord objects that have a belongs_to ... has_many association, with the has_many association being custom-made. Example:

First AR object:

class Car < Vehicle
    has_many :wheels, class_name: "RoundObject", foreign_key: :vehicle_id, conditions: "working = 1"

    validates_presence_of :wheels
    ...
end

Second AR object:

class RoundObject < ActiveRecord::Base
    belongs_to :vehicle
    ...
end

Please note that the above is not indicative of my app's function, simply to outline the association between my two AR objects.

The issue I'm having is that, when I reset the cache (and thus my Rails app re-caches all AR objects in the database), when it comes time for the RoundObject object to get re-cached, it makes multiple calls to the database, one for each unique vehicle_id associated with the collection of RoundObjects. The SQL commands being run are output to the console, so this is what my output looked like:

  RoundObject Load (2.0ms)  SELECT `round_objects`.* FROM `round_objects` WHERE `round_objects`.`vehicle_id` = 28 AND (active = 1)
  RoundObject Load (1.0ms)  SELECT `round_objects`.* FROM `round_objects` WHERE `round_objects`.`vehicle_id` = 29 AND (active = 1)
  RoundObject Load (2.0ms)  SELECT `round_objects`.* FROM `round_objects` WHERE `round_objects`.`vehicle_id` = 30 AND (active = 1)

My app has several other AR objects that use the built-in has_many association without any modifications, and I notice that they only hit the database once when resetting the cache. For instance:

Micropost Load (15.0ms)  SELECT `microposts`.* FROM `microposts` INNER JOIN `posts` ON `posts`.`id` = `microposts`.`post_id` WHERE `microposts`.`active` = 1 AND `posts`.`active` = 1

My question is, how can I make my AR object only hit the database once on cache reset, while still maintaining the custom has_many association I need? Can I manually force a join on the SQL query being called, and will this help?

Thank you!

Upvotes: 3

Views: 314

Answers (1)

Babar
Babar

Reputation: 1202

You can use includes method while calling your Vehicle object to include the RoundObject.
It will go like this:

Vehicle.where(conditions_for_getting_data).includes(:round_object)

Upvotes: 3

Related Questions