2010-04-29 18 views
10

Tôi không biết tại sao tôi không thể hình dung ra điều này, tôi nghĩ nó khá đơn giản. Tôi có hai mô hình (xem bên dưới). Tôi đang cố gắng đưa ra một phạm vi được đặt tên cho SupplierCategory có thể tìm thấy tất cả (các) Nhà cung cấp (bao gồm: nhà cung cấp) mà Nhà cung cấp liên quan không có sản phẩm nào.ActiveRecord tìm thấy tất cả các bậc phụ huynh có con liên quan

Tôi đã thử một thẳng lên tham gia, named_scope :with_suppliers, :joins => :suppliers mà mang lại cho tôi chỉ mục với các nhà cung cấp, nhưng nó mang lại cho tôi mỗi hạng mục liệt kê riêng, vì vậy nếu một thể loại có 2 nhà cung cấp, tôi nhận được các loại gấp đôi trong mảng trả về:

Hiện nay tôi đang sử dụng:

named_scope :with_suppliers, :include => :suppliers 

và sau đó theo quan điểm của tôi, tôi đang sử dụng:

<%= render :partial => 'category', :collection => @categories.find_all{|c| !c.suppliers.empty? } %> 

Không chính xác hùng hồn nhưng illustrat es những gì tôi đang cố gắng đạt được.

Lớp Định nghĩa

class SupplierCategory < AR 
    has_many :suppliers, :order => "name" 
end 

class Supplier < AR 
    belongs_to :supplier 
end 
+0

Trong lớp 'Subbplier' bạn có nghĩa là' thuộc_to: supplier_category'? – klew

Trả lời

12

Dưới đây là thêm một cách tiếp cận:

named_scope :with_suppliers, :include => :suppliers, 
          :conditions => "suppliers.id IS NOT NULL" 

này hoạt động vì Rails sử dụng OUTER THAM GIA cho include khoản. Khi không tìm thấy hàng phù hợp, truy vấn trả về giá trị NULL cho cột nhà cung cấp. Do đó, kiểm tra NOT NULL trả về các hàng phù hợp.

Rails 4

scope :with_suppliers, { includes(:steps).where("steps.id IS NOT NULL") } 

Hoặc sử dụng một phương pháp tĩnh:

def self.with_suppliers 
    includes(:steps).where("steps.id IS NOT NULL") 
end 

Lưu ý:

Giải pháp này tải háo hức nhà cung cấp.

categories = SupplierCategory.with_suppliers 
categories.first.suppliers #loaded from memory 
+0

Chắc chắn gọn gàng nhất của tất cả các giải pháp và hoạt động hoàn hảo !! Cảm ơn – brad

+1

Cập nhật cho đường ray 4: 'phạm vi: in_use, -> {bao gồm (: bước) .where ("steps.id IS NOT NULL")} ' và nó đối ' phạm vi: not_in_use, -> { bao gồm (: bước) .đây ("steps.id IS NULL")} ' – soychicka

1

tôi tin rằng nó sẽ là một cái gì đó giống như

#model SupplierCategory 
named_scope :with_suppliers, 
    :joins => :suppliers, 
    :select => "distinct(supplier_categories), supplier_categories.*", 
    :conditions => "suppliers.supplier_categories_id = supplier_categories.id" 

Hãy cho tôi biết nếu nó làm việc cho bạn.

Edit: Sử dụng ý tưởng fl00r của:

named_scope :with_suppliers, 
    :joins => :suppliers, 
    :select => "distinct(supplier_categories), supplier_categories.*", 
    :having => "count(supliers.id) > 0" 

Tôi tin rằng đây là cách nhanh hơn.

+1

Bạn có chắc chắn bạn nên sử dụng các dạng số ít của mô hình supplier_category thay vì supplier_categories? – fl00r

+0

no = P tks cho điều đó. –

3
class SupplierCategory < AR 
    has_many :supliers 

    def self.with_supliers 
    self.all.reject{ |c| c.supliers.empty? } 
    end 
end 

SupplierCategory.with_supliers 
#=> Array of SuplierCategories with supliers 

Một cách khác linh hoạt hơn bằng named_scope

class SupplierCategory < AR 
    has_many :supliers 
    named_scope :with_supliers, :joins => :supliers, :select => 'distinct(suplier_categories.id), suplier_categories.*', :having => "count(supliers.id) > 0" 
end 

SupplierCategory.with_supliers(:all, :limit => 4) 
#=> first 4 SupplierCategories with suppliers 
+0

Tôi tin rằng việc sử dụng 'join' nhanh hơn phải không? Tôi không biết nếu nó có liên quan trong trường hợp của ông ... nhưng tôi tò mò = P –

+0

có, bạn nói đúng, vì vậy tôi đã thêm giải pháp với tham gia – fl00r

+1

Mã của bạn sẽ trả về dữ liệu trùng lặp do tham gia. –

3

phiên bản đơn giản hơn:

named_scope :with_suppliers, :joins => :suppliers, :group => :id 

Nếu bạn muốn sử dụng nó thường xuyên, xem xét sử dụng counter_cache.

+0

+1 súc tích .... –

Các vấn đề liên quan