Whenever I instantiate a new ActiveRecord
model (one that has not been persisted to the database) and attempt to access some various associations on the built model, the Rails query builder will sometimes:
- Add a
(1=0)
predicate to thewhere
clause of the query. - Add a 'distinct` clause to the select statement.
I think this only occurs when the has_many :through
association is joining two or more tables.
I want to know why it adds the (1=0)
predicate as well as the distinct
clause. For the (1=0)
predicate, it shouldn't matter if the new model has been saved to the database or not (right?). I have no idea why the distinct
clause is being added.
I have a simple example below.
class Assignment < ActiveRecord::Base
has_many :assignment_attachments
has_many :attachments, through: :assignment_attachments
end
class AssignmentAttachment < ActiveRecord::Base
belongs_to :assignment
belongs_to :attachment
end
class Attachment < ActiveRecord::Base
has_many :assignment_attachments
has_many :assignments, through: :assignment_attachments
end
class Submission < ActiveRecord::Base
belongs_to :assignment
has_many :assignment_attachments, through: :assignment
has_many :attachments, through: :assignment
end
s = Submission.new(assignment: Assignment.first)
s.assignment #=> #<Assignment ...>
s.assignment_attachments #=> [#AssignmentAttachment id: '1'>, #AssignmentAttachment assignment_id: '1', attachment_id: '1' ...>]
s.attachments #=> []
Here's the sql query for s.attachments
:
SELECT DISTINCT attachments.*
FROM attachments
INNER JOIN assignment_attachments ON attachments.id = assignment_attachments.attachment_id
INNER JOIN assignments ON assignment_attachments.assignment_id = assignments.id
WHERE assignments.id = 'a0dbfdc7-0d67-4aad-ad06-6a7a5a91d2d0' AND (1=0)
Located somewhere deep in one of the subtrees of the abstract syntax tree that arel builds:
# the 'distinct' select clause
#<Arel::Nodes::SelectCore:0x007ffe43d45be0
@groups=[],
@having=nil,
@projections=
[#<struct Arel::Attributes::Attribute
relation=
#<Arel::Table:0x007ffe45a7be58
@aliases=[],
@columns=nil,
@engine=
Attachment(name: string, description: text, created_at: datetime, updated_at: datetime, required: boolean, id: uuid, slug: string, file_types: string),
@name="attachments",
@primary_key=nil,
@table_alias=nil>,
name="*">],
@set_quantifier=#<Arel::Nodes::Distinct:0x007ffe43d44dd0>,
...
# the (1=0) predicate
@wheres=
[#<Arel::Nodes::And:0x007ffe43d45028
@children=
[#<Arel::Nodes::Equality:0x007ffe45958788
@left=
#<struct Arel::Attributes::Attribute
relation=
#<Arel::Table:0x007ffe45958e68
@aliases=[],
@columns=nil,
@engine=ActiveRecord::Base,
@name="assignments",
@primary_key=nil,
@table_alias=nil>,
name="id">,
@right=#<Arel::Nodes::BindParam:0x007ffe45958878>>,
#<Arel::Nodes::Grouping:0x007ffe43d45050 @expr="1=0">]>]
Do you know why arel is building the distinct
clause and the (1=0)
predicate? I can use some workarounds to get what I want - however, I would love to be able to investigate and find out why and how this tree is built.
Thanks for any/all advice.