60 Experience
0 Lessons Completed
0 Questions Solved


I don't quite know why it works but passing a string to includes instead of a symbol returns both labels.

> Issue.by_labels('bug').includes('labels', 'language').first.labels.map(&:name)
=> ["bug", "help wanted"]

I hope someone here can help me. There's a lot to ActiveRecord I'm yet to understand and I'm a little lost at the moment.

I have three models. Issue, Language, Labels.

An issue has a language and many labels. Languages and labels have many issues.

Because issues and labels have a many to many relationship, I have created a join table tags. (I suppose I could chose a more appropriate name.)

class Label < ApplicationRecord
  has_many :tags
  has_many :issues, through: :tags

class Issue < ApplicationRecord
  has_many :tags
  has_many :labels, through: :tags
  belongs_to :language

class Tag < ApplicationRecord
  belongs_to :issue
  belongs_to :label

I want to be able to filter issues by label or language. To that end, I've added two scopes to Issue.

scope :by_labels, lambda { |labels|
  joins(:labels).where(labels: { name: labels })

scope :by_language, lambda { |language|
  joins(:language).where(languages: { name: language })

I can search for an issue by a single label like so:

> Issue.by_labels('bug').first.labels.map(&:name)
=> ["bug", "help wanted"]

Now, in my controller I want to eager load labels so not to end up with N+1 queries. I use includes:

  @issues = Issue.by_labels('bug').includes(:labels, :language)

However, I now see that only the label specified in the where query is returned:

> Issue.by_labels('bug').includes(:labels, :language).first.labels.map(&:name)
=> ["bug"]

I need each issue row to point to all of its labels. ["bug", "help wanted"] not ["bug"].

Why is it returning the single label? What is includes doing that it doesn't return all the labels?

The executed SQL is:

  SELECT "issues"."id" AS t0_r0, "issues"."assigned" AS t0_r1,
  "issues"."description" AS t0_r2, "issues"."repo_name" AS t0_r3,
  "issues"."title" AS t0_r4, "issues"."url" AS t0_r5,
  "issues"."user_avatar_url" AS t0_r6, "issues"."created_at" AS t0_r7,
  "issues"."updated_at" AS t0_r8, "issues"."language_id" AS t0_r9,
  "labels"."id" AS t1_r0, "labels"."name" AS t1_r1, "labels"."issue_id" AS
  t1_r2, "labels"."created_at" AS t1_r3, "labels"."updated_at" AS t1_r4,
  "languages"."id" AS t2_r0, "languages"."name" AS t2_r1,
  "languages"."color" AS t2_r2, "languages"."created_at" AS t2_r3,
  "languages"."updated_at" AS t2_r4 FROM "issues" INNER JOIN "tags" ON
  "tags"."issue_id" = "issues"."id" INNER JOIN "labels" ON "labels"."id" =
  "tags"."label_id" LEFT OUTER JOIN "languages" ON "languages"."id" =
  "issues"."language_id" WHERE "labels"."name" = ? ORDER BY
  "issues"."created_at" DESC  [["name", "bug"]]

What should I be doing to ensure each issue is returned with all of its corresponding labels?

Any help would be appreciated.

Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

© 2023 GoRails, LLC. All rights reserved.