简体   繁体   English

基于has_many作用域计数的Rails活动记录作用域

[英]Rails active record scope based on count of has_many scope

I have Order model and a Container model with a scope as below: 我有订单模型和容器模型,范围如下:

class Order < ActiveRecord::Base
  has_many :containers, inverse_of: :order, dependent: :destroy
end

class Container < ActiveRecord::Base
  scope :full_pickup_ready, -> { where.not(full_pickup_ready_date: nil) }
end

The order model has a field call quantity which represents the quantity of containers the order requires but is not necessarily the size of the containers association as not all container data is entered at the time of order creation. 订单模型具有一个现场呼叫quantity ,该数量代表订单所需的容器数量,但不一定是容器关联的大小,因为在创建订单时并未输入所有容器数据。

I would like to have a scope on the Order model based on whether the count of the containers with a full_pickup_ready_date is less than the quantity field of the order. 我想根据是否具有full_pickup_ready_date的容器的数量小于订单的数量字段来确定Order模型的范围。

I know I can use merge on the order model to access the scope on the containers like this: 我知道我可以在订单模型上使用合并来访问容器的范围,如下所示:

def self.at_origin
  joins(:containers).merge(Container.full_pickup_ready).uniq
end

but how can I limit the scope to orders where the total number of containers with a full_pickup_ready_date is less that the quantity field on the order? 但是如何将范围限制为具有full_pickup_ready_date的容器总数小于订单上的数量字段的订单?

UPDATE: this is reasonably close, but I don't think using the select is efficient: 更新:这是相当接近的,但我认为使用select效率不高:

includes(:containers).select {|o| o.containers.full_pickup_ready.size < o.quantity }

If you're willing to forgo reuse of the scope on Container , then you should be able to use something like: 如果您愿意放弃在Container上重用该作用域,那么您应该可以使用以下方法:

# scope on Order
joins(:containers)
  .group("orders.id")
  .having("count(CASE WHEN full_pickup_ready_date THEN 1 END) < orders.quantity")

I think you need to get this SQL query to work for you. 我认为您需要获取此SQL查询才能为您工作。 So the idea is to get the SQL query right, and then translate it to "Rails". 因此,其想法是正确获取SQL查询,然后将其转换为“ Rails”。

SQL SQL

If I am correct, this should be the SQL query you want to achieve. 如果我是正确的话,这应该是您要实现的SQL查询。 Maybe you can try it in your rails db 也许您可以在rails db尝试

SELECT orders.* 
FROM orders JOIN containers 
WHERE containers.id = orders.id 
AND ( 
  SELECT COUNT(containers.id) 
  FROM containers 
  WHERE containers.full_pickup_ready_date IS NOT NULL 
) < orders.quantity;

ActiveRecord ActiveRecord的

If this is the right query, then we can do this using rails 如果这是正确的查询,那么我们可以使用rails

Order.joins(:containers).where("( SELECT COUNT(containers.id) FROM containers WHERE containers.full_pickup_ready_date IS NOT NULL ) < orders.quantity")

This should return an ActiveRecord relation. 这应该返回一个ActiveRecord关系。 You could also do this: 您也可以这样做:

sql = %{
  SELECT orders.* 
  FROM orders JOIN containers 
  WHERE containers.id = orders.id 
  AND ( 
    SELECT COUNT(containers.id) 
    FROM containers 
    WHERE containers.full_pickup_ready_date IS NOT NULL 
  ) < orders.quantity;
}.gsub(/\s+/, " ").strip

Order.find_by_sql(sql)

Just add this in a class method (better than scope IMHO) and you are good to go. 只需将其添加到类方法中(比作用域恕我直言更好),就可以了。

So, your Order class should look like this: 因此,您的Order类应如下所示:

class Order < ActiveRecord::Base
  has_many :containers, inverse_of: :order, dependent: :destroy

  def self.gimme_a_query_name
    joins(:containers).where("( SELECT COUNT(containers.id) FROM containers WHERE containers.full_pickup_ready_date IS NOT NULL ) < orders.quantity")
  end

  def self.gimme_another_query_name
    sql = %{
      SELECT orders.* 
      FROM orders JOIN containers 
      WHERE containers.id = orders.id 
      AND ( 
        SELECT COUNT(containers.id) 
        FROM containers 
        WHERE containers.full_pickup_ready_date IS NOT NULL 
      ) < orders.quantity;
    }.gsub(/\s+/, " ").strip
    find_by_sql(sql)
  end
end

I have no way to try this, but it should work with few tweak to get the SQL query right. 我没有办法尝试此操作,但是应该进行一些调整才能使SQL查询正确。

I hope this help! 希望对您有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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