简体   繁体   中英

In Rails5, how do I return the union of two scopes or combine them into one?

I'm struggling to either return the union of two scopes or combine them into one in my Rails app. The outcome I'm looking for is to retrieve all orders that satisfy either of the scopes: Order.with_buyer_like or the Order.with_customer_like. That is I'm looking for the union of the sets. Importantly, I need these to be returned as an ActiveRecord::Relation, rather than an array. Otherwise, I'd just do

results =  Order.with_buyer_like + Order.with_customer_like

I've also tried to use the "or" operator but get an error:

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

I've also tried combining the scopes into one, but I can't quite get it to work.

Here's my setup:

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

This blog has good explanation of issue you are facing.

To summarize here, you have to make sure the joins , includes , select (in short structure of AR data to be fetched) is consistent between both the scopes.

This syntax is the way to go as long as you make sure both the scopes have same joins.

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

To take first step, check if this works(not recommended though):

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

I would recommend to move away from joins and use sub-query style of querying if you are looking for only Order data in output.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM