0

I'm trying to eager load a Course model with some associated models, Community and Package. The relationships between them are as follows:

class Community < ApplicationRecord
  ...
  has_many :courses, dependent: :destroy
end
class Course < ApplicationRecord
  ...
  belongs_to :community, optional: true

  has_many :package_course_relationships, dependent: :destroy
  has_many :packages, through: :package_course_relationships
  has_many :available_packages, -> { available }, through: :package_course_relationships, source: :package
end
class Package < ApplicationRecord
  ...
  has_many :package_course_relationships, dependent: :destroy
  has_many :courses, through: :package_course_relationships

  scope :available, -> { where(archived: false) }
end
class PackageCourseRelationship < ApplicationRecord
  belongs_to :package
  belongs_to :course
end

The problem I am facing is that when calling

Course.includes(:community, :available_packages)
      .where(communities: { is_active: true }, archived: false, is_draft: false, is_completed: false, is_default_template: false, visibility: %i[unlisted public])
      .find(3)

two sql queries are made:

SELECT DISTINCT "courses"."id" FROM "courses" 
LEFT OUTER JOIN "communities" ON "communities"."id" = "courses"."community_id" 
LEFT OUTER JOIN "package_course_relationships" ON "package_course_relationships"."course_id" = "courses"."id" 
LEFT OUTER JOIN "packages" ON "packages"."id" = "package_course_relationships"."package_id" AND "packages"."archived" = $1 
WHERE "communities"."is_active" = $2 AND "courses"."archived" = $3 AND "courses"."is_draft" = $4 AND "courses"."is_completed" = $5 AND "courses"."is_default_template" = $6 AND "courses"."visibility" IN ($7, $8) AND "courses"."id" = $9 
LIMIT $10  
[["archived", false], ["is_active", true], ["archived", false], ["is_draft", false], ["is_completed", false], ["is_default_template", false], ["visibility", "unlisted"], ["visibility", "public"], ["id", 3], ["LIMIT", 1]]
SELECT "courses"."id" AS t0_r0, "courses"."name" AS t0_r1, "courses"."description" AS t0_r2, "courses"."meeting_times" AS t0_r3, "courses"."start_date" AS t0_r4, "courses"."end_date" AS t0_r5, "courses"."is_default" AS t0_r6, "courses"."created_at" AS t0_r7, "courses"."updated_at" AS t0_r8, "courses"."community_id" AS t0_r9, "courses"."is_draft" AS t0_r10, "courses"."is_private" AS t0_r11, "courses"."archived" AS t0_r12, "courses"."is_completed" AS t0_r13, "courses"."program_curriculum_id" AS t0_r14, "courses"."is_template" AS t0_r15, "courses"."is_default_template" AS t0_r16, "courses"."golfer_limit" AS t0_r17, "courses"."marketing_video_url" AS t0_r18, "courses"."is_featured" AS t0_r19, "courses"."photo_url" AS t0_r20, "courses"."organization_id" AS t0_r21, "courses"."lesson_plan_id" AS t0_r22, "courses"."payment_method" AS t0_r23, "courses"."registration_starts_at" AS t0_r24, "courses"."registration_ends_at" AS t0_r25, "courses"."course_category_id" AS t0_r26, "courses"."personalized_video_url" AS t0_r27, "courses"."visibility" AS t0_r28, "communities"."id" AS t1_r0, "communities"."name" AS t1_r1, "communities"."description" AS t1_r2, "communities"."address_id" AS t1_r3, "communities"."created_at" AS t1_r4, "communities"."updated_at" AS t1_r5, "communities"."is_active" AS t1_r6, "communities"."email" AS t1_r7, "communities"."phone_number" AS t1_r8, "communities"."bio" AS t1_r9, "communities"."is_public" AS t1_r10, "communities"."points" AS t1_r11, "communities"."booking_url" AS t1_r12, "communities"."monthly_points" AS t1_r13, "communities"."weekly_points" AS t1_r14, "communities"."support_rating" AS t1_r15, "communities"."representative_id" AS t1_r16, "communities"."community_stage_id" AS t1_r17, "communities"."additional_note" AS t1_r18, "communities"."goals_note" AS t1_r19, "communities"."completed_onboarding" AS t1_r20, "communities"."season_start_date" AS t1_r21, "communities"."season_end_date" AS t1_r22, "communities"."mailing_address" AS t1_r23, "communities"."community_type" AS t1_r24, "communities"."network_date" AS t1_r25, "communities"."purchased_upsell_products" AS t1_r26, "communities"."map_filters" AS t1_r27, "communities"."sales_rep_id" AS t1_r28, "communities"."pinned_ads" AS t1_r29, "communities"."level" AS t1_r30, "communities"."onboarding_checklist_url" AS t1_r31, "communities"."resource_folder_url" AS t1_r32, "communities"."show_onboarding_banner" AS t1_r33, "communities"."selected_stripe_connected_account_id" AS t1_r34, "communities"."license_type" AS t1_r35, "communities"."application_fee" AS t1_r36, "communities"."pipedrive_deal_id" AS t1_r37, "communities"."pipedrive_organization_id" AS t1_r38, "communities"."golf_genius_id" AS t1_r39, "communities"."application_fee_type" AS t1_r40, "communities"."currency_code" AS t1_r41, "communities"."timezone" AS t1_r42, "packages"."id" AS t2_r0, "packages"."name" AS t2_r1, "packages"."description" AS t2_r2, "packages"."price" AS t2_r3, "packages"."archived" AS t2_r4, "packages"."creator_id" AS t2_r5, "packages"."community_id" AS t2_r6, "packages"."created_at" AS t2_r7, "packages"."updated_at" AS t2_r8 FROM "courses"
LEFT OUTER JOIN "communities" ON "communities"."id" = "courses"."community_id"
LEFT OUTER JOIN "package_course_relationships" ON "package_course_relationships"."course_id" = "courses"."id"
LEFT OUTER JOIN "packages" ON "packages"."id" = "package_course_relationships"."package_id" AND "packages"."archived" = $1
WHERE "communities"."is_active" = $2 AND "courses"."archived" = $3 AND "courses"."is_draft" = $4 AND "courses"."is_completed" = $5 AND "courses"."is_default_template" = $6 AND "courses"."visibility" IN ($7, $8) AND "courses"."id" = $9 AND "courses"."id" = $10
[["archived", false], ["is_active", true], ["archived", false], ["is_draft", false], ["is_completed", false], ["is_default_template", false], ["visibility", "unlisted"], ["visibility", "public"], ["id", 3], ["id", 3]]

I am not very experienced with Rails and I think I might have written the ActiveRecord call wrong, but I can't guess why this is resulting in two similar SQL queries.

I don't really know what to try, but I am expecting only one query to be made. It is confusing to me why the first query that only selects the id of the course is made.

2
  • I'm not sure why you're getting two queries, but your query ends with find(3) so it should just return the course with id=3. Given that, what is the purpose of the rest of the query? Just do Course.find(3) should give you the same result. Commented Feb 27, 2024 at 13:32
  • @LesNightingill The query is used in an endpoint and I need the associated models preloaded for further processing. I replaced find(params[:id]) with find(3) to simplify the example given and to focus on the double-query problem. Commented Feb 27, 2024 at 15:48

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.