我有Order模型和Container模型,其范围如下:
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的容器的数量是否小于订单的数量字段。
我知道我可以在订单模型上使用merge来访问容器上的范围,如下所示:
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 }
答案 0 :(得分:3)
如果您愿意放弃Container
上范围的重复使用,那么您应该可以使用以下内容:
# scope on Order
joins(:containers)
.group("orders.id")
.having("count(CASE WHEN full_pickup_ready_date THEN 1 END) < orders.quantity")
答案 1 :(得分:1)
我认为你需要让这个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查询正确。
我希望这有帮助!