关系传递给#or的关系必须在结构上兼容.不兼容的值:[:参考]



我有两个查询,我需要一个 or,即我想要的结果是第一个查询或第二个查询。

第一个查询是一个简单的where(),可获取所有可用的项目。

@items = @items.where(available: true)

第二个包括一个join()并提供当前用户的项目。

@items =
  @items
  .joins(:orders)
  .where(orders: { user_id: current_user.id})

我试图以各种形式将它们与Rails的or()方法相结合,包括:

@items =
  @items
  .joins(:orders)
  .where(orders: { user_id: current_user.id})
  .or(
    @items
    .joins(:orders)
    .where(available: true)
  )

但是我一直遇到此错误,我不确定如何修复它。

Relation passed to #or must be structurally compatible. Incompatible values: [:references]

在github上有一个已知问题。

根据此评论,您可能需要覆盖structurally_incompatible_values_for_or以克服问题:

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

也总是有一个使用SQL的选项:

@items
  .joins(:orders)
  .where("orders.user_id = ? OR items.available = true", current_user.id)

您可以以这种良好的旧方式编写查询,以避免错误

@items = @items.joins(:orders).where("items.available = ? OR orders.user_id = ?", true, current_user.id)

希望有帮助!

hacky解决方案:在.or之后执行所有.joins。这将Checker隐藏了有问题的.joins。也就是说,将原始问题中的代码转换为...

@items =
  @items
  .where(orders: { user_id: current_user.id})
  .or(
    @items
    .where(available: true)
  )
  .joins(:orders) # sneaky, but works! 😈

更一般地,以下两行将失败

A.joins(:b).where(bs: b_query).or(A.where(query))  # error! 😞 
A.where(query).or(A.joins(:b).where(bs: b_query))  # error! 😞 

但重新排列如下,您可以逃避检查器:

A.where(query).or(A.where(bs: b_query)).joins(:b)  # works 😈 

这起作用,因为所有检查都发生在.or()方法内。在下游结果上,这是幸福的Shennanigans。

一个缺点当然不是很好。

我遇到了同一问题,但是代码是在另一个地方定义的,很难直接更改。

# I can't change "p"
p = Post.where('1 = 1').distinct # this could also be a join

我需要向其添加or语句

p.or(Post.where('2 = 2'))

以下代码不会引起错误,因为它具有distinct,例如初始关系。

p.or(Post.where('2 = 2').distinct)

只要您知道这种关系,它的问题就可以工作。它可能具有或没有joindistinct

这项工作不管是什么关系:

p.or(p.unscope(:where).where('2 = 2'))
=> SELECT DISTINCT `posts`.* FROM `posts` WHERE ((1 = 1) OR (2 = 2))

当您尝试结合同一类型的两个多活动记录时,会发生这种情况,但是其中一个具有加入值或一个值,或者包括值,或者在您的情况下为参考值,另一个没有。因此,我们需要匹配它们之间的值,我找到了一种一般的方法来执行此操作,而又不知道实际值。

items_1 = @items.joins(:orders)
                .where(orders: { user_id: current_user.id})
items_2 = @items.where(available: true)
                .joins(items_1.joins_values)
                .includes(items_1.includes_values)
                .references(items_1.references_values)
@items = items_1.or(items_2)

只是解决它!

  def exec_or_statement(q1, q2)
    klass = q1.klass
    key = klass.primary_key
    query_wrapper_1 = {}
    query_wrapper_1[key] = q1
    query_wrapper_2 = {}
    query_wrapper_2[key] = q2
    klass.where(query_wrapper_1).or(klass.where(query_wrapper_2))
  end
  query_1 = @items.where(available: true)
  query_2 =
    @items
    .joins(:orders)
    .where(orders: { user_id: current_user.id})
  
  exec_or_statement(query_1, query_2)

相关内容

  • 没有找到相关文章

最新更新