Relation passed to #or must be structurally compatible. Incompatible values: [:references]
There is a known issue about it on Github.
According to this comment you might want to override the structurally_incompatible_values_for_or
to overcome the issue:
def structurally_incompatible_values_for_or(other) Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } + (Relation::MULTI_VALUE_METHODS - [:eager_load, :references, :extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } + (Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }end
Also there is always an option to use SQL:
@items .joins(:orders) .where("orders.user_id = ? OR items.available = true", current_user.id)
You can write the query in this good old way to avoid error
@items = @items.joins(:orders).where("items.available = ? OR orders.user_id = ?", true, current_user.id)
Hope that helps!
Hacky workaround: do all your .joins
after the .or
. This hides the offending .joins
from the checker. That is, convert the code in the original question to...
@items = @items .where(orders: { user_id: current_user.id}) .or( @items .where(available: true) ) .joins(:orders) # sneaky, but works! 😈
More generally, the following two lines will both fail
A.joins(:b).where(bs: b_query).or(A.where(query)) # error! 😞
A.where(query).or(A.joins(:b).where(bs: b_query)) # error! 😞
but rearrange as follows, and you can evade the checker:
A.where(query).or(A.where(bs: b_query)).joins(:b) # works 😈
This works because all the checking happens inside the .or()
method. It's blissfully unaware of shennanigans on its downstream results.
One downside of course is it doesn't read as nicely.