ActiveRecord find all parents that have associated children

后端 未结 4 1484
生来不讨喜
生来不讨喜 2020-12-09 20:16

I don\'t know why I can\'t figure this out, I think it should be fairly simple. I have two models (see below). I\'m trying to come up with a named scope for SupplierCatego

相关标签:
4条回答
  • 2020-12-09 20:37
    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
    

    Another way more flexible using 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 讨论(0)
  • 2020-12-09 20:45

    Here is one more approach:

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

    This works because Rails uses OUTER JOIN for include clause. When no matching rows are found the query returns NULL values for supplier columns. Hence NOT NULL check returns the matching rows.

    Rails 4

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

    Or using a static method:

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

    Note:

    This solution eager loads suppliers.

    categories = SupplierCategory.with_suppliers
    categories.first.suppliers #loaded from memory
    
    0 讨论(0)
  • 2020-12-09 20:54

    Simpler version:

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

    If you want to use it frequently, consider using counter_cache.

    0 讨论(0)
  • 2020-12-09 20:57

    I believe it would be something like

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

    Let me know if it works for you.

    Edit: Using fl00r's idea:

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

    I believe this is the faster way.

    0 讨论(0)
提交回复
热议问题