RamanSM
RamanSM

Reputation: 283

rails includes query loading entire data for included models

I have a rails application where I have following models.

BookingHotel
    has_many :hotel_picture_partners, through: :hotel_pictures
    has_many :booking_hotel_partner_details, dependent: :destroy

BookingHotelPartnerDetail
    belongs_to :booking_hotel

HotelPicturePartner
    belongs_to :hotel_picture, dependent: :destroy

I have a query as follows

@booking_hotel_partner_details = BookingHotelPartnerDetail.unscoped.select(:id, :booking_hotel_id, :partner_booking_hotel_id).includes(booking_hotel: :hotel_picture_partners) 

This puts memory under pressure as it loads all data for included models.

Is there a way I can only load selective fields from booking_hotels & hotel_picture_partners tables ?

Also I want to get an activerecord array as response.

Upvotes: 1

Views: 139

Answers (2)

Lorin Thwaits
Lorin Thwaits

Reputation: 399

Your project is probably already pretty far along, but for anyone else wanting this behaviour I've released a patch that filters columns if you have a .select(...) along with .includes(...) or .eager_load(...). It's now included in a data-related gem I maintain, The Brick.

It works by overriding ActiveRecord::Associations::JoinDependency.apply_column_aliases() like this.

In order to enable this selective behaviour, add the special column name :_brick_eager_load as the first entry in your .select(...), which turns on the filtering of columns while the aliases are being built out. Here's an example based on your code:

@booking_hotel_partner_details =
  BookingHotelPartnerDetail.unscoped
                           .includes(booking_hotel: :hotel_picture_partners)
                           .select(:_brick_eager_load, :id, :partner_booking_hotel_id, 'booking_hotel.name', 'hotel_picture_partners.notes')

Feel free to add myraid additional columns from any table as strings in the same way as the last two sample items I put into the .select(...).

Because foreign keys are essential to have everything be properly associated, they are automatically added, so you do not need to include :booking_hotel_id in your select list.

Hope it can save you both query time and some RAM!

Upvotes: 0

Andrey Saleba
Andrey Saleba

Reputation: 2197

pluck method loads only attributes, without loading whole models. check it: http://apidock.com/rails/ActiveRecord/Calculations/pluck.

Try to rewrite it like this: BookingHotelPartnerDetail.unscoped.select('booking_hotels.id as bh_id', 'hotel_picture_partners.id as hpp_id').joins(booking_hotel: :hotel_picture_partners)

Upvotes: 1

Related Questions