【问题标题】:In Rails5, how do I return the union of two scopes or combine them into one?在 Rails 5 中,我如何返回两个范围的并集或将它们合并为一个?
【发布时间】:2018-01-08 20:11:17
【问题描述】:

我正在努力在我的 Rails 应用程序中返回两个范围的联合或将它们合并为一个。我正在寻找的结果是检索满足以下任一范围的所有订单:Order.with_buyer_like 或 Order.with_customer_like。那就是我正在寻找集合的并集。重要的是,我需要将这些作为 ActiveRecord::Relation 而不是数组返回。否则,我就这么做了

results =  Order.with_buyer_like + Order.with_customer_like

我也尝试使用“或”运算符,但出现错误:

Order.with_seller_like('pete').or(Order.with_customer_like('pete'))
ArgumentError: Relation passed to #or must be structurally compatible. Incompatible values: [:joins]

我也尝试过将这些作用域合二为一,但我不能完全让它发挥作用。

这是我的设置:

class Company
  has_many :stores
end 

class Store
  belongs_to :company
end

class Order
  belongs_to :buying_store, class_name: 'Store', foreign_key: 'buying_store_id', required: true 
  belongs_to :selling_store, class_name: 'Store', foreign_key: 'selling_store_id', required: true

  scope :with_buyer_like, ->(search_term) { joins(buying_store: [:company], :customer).where(['stores.name LIKE ? OR companies.name LIKE ?', "%#{search_term.gsub(/ /, '_').downcase}%", "%#{search_term.gsub(/ /, '_').downcase}%"]) }

  scope :with_customer_like, ->(search_term) { joins(:customer).where(['first_name LIKE ? OR last_name LIKE ? OR mobile_number LIKE ? OR email LIKE ?', "%#{search_term.gsub(/ /, '_').downcase}%", "%#{search_term.gsub(/ /, '_').downcase}%", "%#{search_term.gsub(/ /, '_').downcase}%", "%#{search_term.gsub(/ /, '_').downcase}%"] ) } 
end

【问题讨论】:

  • 错误表示 or 中的连接不兼容(joins 在您的范围内创建)
  • 你试过Order.with_buyer_like('pete').with_customer_like('pete')吗?
  • m.simon,问题在于它给了我集合的交集,而不是联合。
  • Yoshiji 先生 - 我只是不知道该怎么办。每个范围都可以完美地工作。

标签: ruby-on-rails postgresql activerecord arel


【解决方案1】:

This blog 很好地解释了您面临的问题。

在这里总结一下,您必须确保joinsincludesselect(简称为要获取的 AR 数据的结构)在两个范围之间保持一致。

只要确保两个作用域具有相同的连接,此语法就是可行的方法。

Order.with_seller_like('pete').or(Order.with_customer_like('pete'))

要迈出第一步,请检查这是否可行(但不推荐):

Order.where(id: Order.with_seller_like('pete')).or(Order.where(id: Order.with_customer_like('pete')))

如果您在输出中寻找 Order 数据,我建议您远离joins 并使用子查询样式进行查询。

【讨论】:

  • 谢谢,是的。我不确定我是否知道查询的子查询样式是什么?
  • Order.joins(:customer).where("customer.name = 'pete'") 将获得ordercustomer 的详细信息。如果您像 Order.where(customer_id: Customer.where(name: 'pete')) 那样重写它,它将获得相同的订单,而无需任何客户详细信息。如果您可以将scopes 都写成joins 逻辑到where 子句的这种风格,那么您不需要包装器Order.where(id... 函数。
猜你喜欢
  • 2019-03-21
  • 1970-01-01
  • 2021-05-07
  • 2022-11-03
  • 1970-01-01
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 2015-05-26
相关资源
最近更新 更多