How do I use includes to return all columns of associated table?
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
end
class Issue < ApplicationRecord
has_many :tags
has_many :labels, through: :tags
belongs_to :language
...
end
class Tag < ApplicationRecord
belongs_to :issue
belongs_to :label
end
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.