2011-08-20 63 views
3

我正在使用Rails 3.0。我有两个表格:清单和优惠。代理has-many优惠。报价可以有acceptedtruefalse选择集合的补码

我想选择每个没有accepted的报价为true的房源。我试图

Listing.joins(:offers).where('offers.accepted' => false) 

然而,由于上市可以有很多优惠,这个选择具有非公认提供每天上市,即使有该清单的接受的报价。

在这种不明确的情况下,我要的是集合的补:

Listing.joins(:offers).where('offers.accepted' => true) 

我目前的临时解决方案是抓住所有的人,然后做一个过滤器阵列上,像这样:

class Listing < ActiveRecord::Base 
... 
    def self.open 
     Listing.all.find_all {|l| l.open? } 
    end 

    def open? 
     !offers.exists?(:accepted => true) 
    end 
end 

我宁愿如果解决方案运行数据库端的过滤。

回答

1

首先想到的是基本上做你现在正在做的同样的事情,但在数据库中。

scope :accepted, lambda { 
    joins(:offers).where('offers.accepted' => true) 
} 

scope :open, lambda { 
    # take your accepted scope, but just use it to get at the "accepted" ids 
    relation = accepted.select("listings.id") 

    # then use select values to get at those initial ids 
    ids = connection.select_values(relation.to_sql) 

    # exclude the "accepted" records, or return an unchanged scope if there are none 
    ids.empty? ? scoped : where(arel_table[:id].not_in(ids)) 
} 

我敢肯定,这可以更清晰地使用外部进行连接和分组,但它不是:-)

+0

由于马上来找我!这比我的工作速度要快得多。我最惊讶的是,我没有在互联网上找到这个解决方案 - 似乎这将是一个相对普遍的问题。 – OrangeAlmondSoap

+0

一个警告 - 如果没有被接受的答案,那么'ids'是空的。这会使'not_in'失败,并且不会选择任何东西!我在'ids'的声明下面加了'ids | = [0]',它完美的工作。 – OrangeAlmondSoap

+0

哎呀,很好。更新答案。 – numbers1311407