Reputation: 1
class Parent < ApplicationRecord
has_many :children
enum status: {
status1: 0,
status2: 1
}
end
class Child < ApplicationRecord
belongs_to :parent
end
# error
# "Relation passed to #or must be structurally compatible. Incompatible values: [:references]"
combination = Parent.status1.or(Parent.status2.includes(:children).where(children: {name: 'ABC'}))
I want to get the data "status1" or "status2 has children named 'ABC'", but error occurs.
Upvotes: 0
Views: 2629
Reputation: 7524
The or
method takes another relation that has a similar filter pattern, and combines it with the already-existing filters on the object being called.
For example, Parent.status1.or(Parent.status2)
would give you a set of records that have either status: 1
or status: 2
.
(In case someone is not familiar with it, the example in the question also uses enum
, which allows filtering the enum's attribute value using the name of the value. #status1
and #status2
in this case correspond to { status: 0 }
and {status: 1}
respectively.)
In order to call more relation methods to modify the final result, you must call them on the result of calling #or
, like this:
Parent.status1.or(Parent.status2).includes(:children).where(children: {name: 'ABC'})
Based on your comment I see now that you want records that either (have status1
) or (have status2
and have a matching children
record).
Note that in order to use a relation in a where
(like where(children: { name: value })
you must join with the related table (joins(:children).where(children: { name: value })
. It seems that ActiveRecord will infer the join if you use only includes
, but that's not documented as far as I can tell. This is why or
sees the two relations as incompatible: one has children
in the references list, while the other does not.
If you write the where
clause by hand as a string, it does not change the references list, so or
does not see the relation as incompatible. When you write a where
clause by hand, you must explicitly use joins
:
Parent.status1.joins(:children).or(Parent.status2.joins(:children).where("children.name = 'ABC'"))
Upvotes: 2
Reputation: 422
You are not calling "includes" on the final or result.
parent = Parent.status1.or(Parent.status2)
parent.includes(:chilren).where(children: {name: "ABC"})
Upvotes: 0