Read more

Howto use ActiveRecord preload with plain SQL inner joins

Emanuel
December 12, 2016Software engineer at makandra GmbH

Like you know from "How to tell ActiveRecord how to preload associations (either JOINs or separate queries)", you can tell ActiveRecord explicitly if it should use a LEFT OUTER JOIN or a separate query to preload associations.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

Here is some special case, where a simple includes is not possible. For the diagram below we want to sort the rides by the translated name of the departure_place and the arrival_place:

6020905239052288.png

Here is the list of features we want to achieve:

This is normally straightforward, but as we are referencing the table we want to order on twice some adjustments need to be made.

Ride
.joins('inner join places as departure_places on ride.departure_place_id = departure_places.id')
.joins('inner join places as arrival_places on ride.arrival_place_id = arrival_places.id')
.joins('inner join place_translations as departure_place_translations on departure_places.id = departure_place_translations.place_id AND departure_place_translations.locale = "en"')
.joins('inner join place_translations as arrival_place_translations on arrival_places.id = arrival_place_translations.place_id AND arrival_place_translations.locale = "en"')
.order('departure_place_translations.name, arrival_place_translations.name')
.where(ride_id: 1)
.paginate(page: 1, per_page: 20)
.preload(
  departure_place: :translations,
  arrival_place: :translations
)
.to_a

What we do here:

  • First make some custom SQL with INNER JOINs where our order constraint can be fulfilled (Power of plain SQL: Using eager_load here is not possible or very painful)
  • Then preload the result set (Power of ActiveRecord: If you don't use ActiveRecord preload you need to manually take care of pagination and ordering after fetching the records by ids)
Posted by Emanuel to makandra dev (2016-12-12 10:42)