4

我有一个简单的父对象,有很多孩子。我试图弄清楚如何使用命名范围来带回具有特定数量孩子的父母。

这可能吗?

class Foo < ActiveRecord::Base
    has_many :bars
    named_scope :with_no_bars, ... # count of bars == 0
    named_scope :with_one_bar, ... # count of bars == 1
    named_scope :with_more_than_one_bar, ... # count of bars > 1
end

class Bar < ActiveRecord::Base
    belongs_to :foo
end

我希望做类似的事情Foo.with_one_bar

我可以在父类上写这样的方法,但我宁愿拥有命名范围的力量

4

2 回答 2

11
class Foo < ActiveRecord::Base
  has_many :bars

  # I don't like having the number be part of the name, but you asked for it.
  named_scope :with_one_bar, :joins => :bars, :group => "bars.foo_id", :having => "count(bars.foo_id) = 1"

  # More generically...
  named_scope :with_n_bars, lambda {|n| {:joins => :bars, :group => "bars.foo_id", :having => ["count(bars.foo_id) = ?", n]}}
  named_scope :with_gt_n_bars, lambda {|n| {:joins => :bars, :group => "bars.foo_id", :having => ["count(bars.foo_id) > ?", n]}}

end

像这样调用:

Foo.with_n_bars(2)
于 2010-05-24T20:43:39.753 回答
6

我会为此使用计数器缓存。因此,您需要以下迁移:

class AddBarCount < ActiveRecord::Migration
  def self.up  
    add_column :foos, :bars_count, :integer, :default => 0  

    Foo.reset_column_information  
    Foo.all.each do |p|  
      p.update_attribute :bars_count, p.bars.length  
    end  
  end  

  def self.down  
    remove_column :foos, :bars_count  
  end
end

比你需要改变你Bar的模型是这样的:

class Bar < ActiveRecord::Base
  belongs_to :foo, :counter_cache => true
end

现在计数bars被缓存在foo模型中,这将加快您对计数的查询bars

然后,您的 named_scopes 也看起来像这样:

#rails 2
named_scope :with_no_bars, :conditions => { :bars_count => 0 }
named_scope :with_one_bar, :conditions => { :bars_count => 1 }
named_scope :with_more_than_one_bar, :conditions => ["bars_count > 1"]

#rails 3 & ruby 1.9+
scope :with_no_bars, where(bars_count: 0)
scope :with_one_bar, where(bars_count: 1)
scope :with_more_than_on_bar, where("bars_count > 1")

#rails 4* & ruby 1.9+
scope :with_no_bars, -> { where(bars_count: 0) }
scope :with_one_bar, -> { where(bars_count: 1) }
scope :with_more_than_one_bar, -> { where("bars_count > 1") }

这样,您每次提出此类请求时都可以节省时间bars计算foo

我在观看有关计数器缓存的 railscast 时产生了这个想法:http ://railscasts.com/episodes/23-counter-cache-column

* Active Record 中的新功能 [Rails 4 Countdown to 2013]

于 2010-05-24T20:57:34.453 回答