繁体   English   中英

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

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

我有订单模型和容器模型,范围如下:

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

订单模型具有一个现场呼叫quantity ,该数量代表订单所需的容器数量,但不一定是容器关联的大小,因为在创建订单时并未输入所有容器数据。

我想根据是否具有full_pickup_ready_date的容器的数量小于订单的数量字段来确定Order模型的范围。

我知道我可以在订单模型上使用合并来访问容器的范围,如下所示:

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

但是如何将范围限制为具有full_pickup_ready_date的容器总数小于订单上的数量字段的订单?

更新:这是相当接近的,但我认为使用select效率不高:

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

如果您愿意放弃在Container上重用该作用域,那么您应该可以使用以下方法:

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

我认为您需要获取此SQL查询才能为您工作。 因此,其想法是正确获取SQL查询,然后将其转换为“ Rails”。

SQL

如果我是正确的话,这应该是您要实现的SQL查询。 也许您可以在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的

如果这是正确的查询,那么我们可以使用rails

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

这应该返回一个ActiveRecord关系。 您也可以这样做:

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)

只需将其添加到类方法中(比作用域恕我直言更好),就可以了。

因此,您的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

我没有办法尝试此操作,但是应该进行一些调整才能使SQL查询正确。

希望对您有所帮助!

暂无
暂无

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

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