我有以下命名范围
class RentableItem < ActiveRecord::Base
named_scope :available_at, lambda{ |starts_at, ends_at| {
:select => "t.*",
:from => "(SELECT ri.*, COALESCE(c1.start_date, '#{starts_at}') AS EarliestAvailable,
COALESCE(c2.end_date, '#{ends_at}') AS LatestAvailable
FROM rentable_items ri
LEFT OUTER JOIN contracts c1 ON (ri.id = c1.rentable_item_id AND c1.start_date BETWEEN '#{starts_at}' AND '#{ends_at}')
LEFT OUTER JOIN contracts c2 ON (ri.id = c2.rentable_item_id AND c2.end_date BETWEEN '#{starts_at}'
AND '#{ends_at}' AND c2.start_date >= c1.end_date))
AS t",
:joins =>"LEFT OUTER JOIN contracts x ON (t.id = x.rentable_item_id AND x.start_date < t.LatestAvailable
AND x.end_date > t.EarliestAvailable)",
:conditions => "x.id IS NULL AND DATEDIFF(t.LatestAvailable, t.EarliestAvailable) >= #{(starts_at.to_date..ends_at.to_date).to_a.size - 1}"
}}
end
对这个 named_scope 的单个调用就像一个魅力,但是当我试图将几个命名范围链接在一起,或者通过一个关联范围访问这个 named_scope 时,它会爆炸。我认为,select 语句和自定义 from 子句是问题所在。也许有人知道如何重写这个 named_scope 以允许链接和限定槽关联?
编辑:
多亏了 Shtéf,它正在工作。
named_scope :available_at, lambda{ |starts_at, ends_at| {
:select => "rentable_items.*",
:from => "(SELECT ri.*, COALESCE(c1.start_date, '#{starts_at}') AS EarliestAvailable,
COALESCE(c2.end_date, '#{ends_at}') AS LatestAvailable
FROM rentable_items ri
LEFT OUTER JOIN contracts c1 ON (ri.id = c1.rentable_item_id AND c1.start_date BETWEEN '#{starts_at}' AND '#{ends_at}')
LEFT OUTER JOIN contracts c2 ON (ri.id = c2.rentable_item_id AND c2.end_date BETWEEN '#{starts_at}'
AND '#{ends_at}' AND c2.start_date >= c1.end_date))
AS rentable_items",
:joins =>"LEFT OUTER JOIN contracts x ON (rentable_items.id = x.rentable_item_id AND x.start_date < rentable_items.LatestAvailable
AND x.end_date > rentable_items.EarliestAvailable)",
:conditions => "x.id IS NULL AND DATEDIFF(rentable_items.LatestAvailable, rentable_items.EarliestAvailable) >= #{(starts_at.to_date..ends_at.to_date).to_a.size - 1}"
}}
这使我现在可以链接范围并通过关联访问它。
轨道生成的双重 where 条件可能只是一个装饰性的小问题(在开始和结束时:
WHERE (`rentable_items`.container_item_id = 1) AND (((size > 10) AND (x.id IS NULL AND DATEDIFF(rentable_items.LatestAvailable, rentable_items.EarliestAvailable) >= 28)) AND (`rentable_items`.container_item_id = 1))