Joe*_*rns 4 activerecord named-scope ruby-on-rails ruby-on-rails-2
我有一个有很多孩子的简单父对象.我正在试图弄清楚如何使用命名范围来带回具有特定数量的孩子的父母.
这可能吗?
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
Run Code Online (Sandbox Code Playgroud)
我希望能做类似的事情 Foo.with_one_bar
我可以在父类上编写类似这样的方法,但我宁愿拥有命名范围的强大功能
jdl*_*jdl 10
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
Run Code Online (Sandbox Code Playgroud)
这样称呼:
Foo.with_n_bars(2)
Run Code Online (Sandbox Code Playgroud)
我会使用计数器缓存.因此,您需要以下迁移:
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
Run Code Online (Sandbox Code Playgroud)
比你需要的更改你的Bar模型如下:
class Bar < ActiveRecord::Base
belongs_to :foo, :counter_cache => true
end
Run Code Online (Sandbox Code Playgroud)
现在计数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") }
Run Code Online (Sandbox Code Playgroud)
这样bars,每次foo发出此类请求时,您都可以节省计算时间.
我有这个想法观看关于计数器缓存的railscast:http://railscasts.com/episodes/23-counter-cache-column
*Active Record中的新功能[2013年Rails 4倒计时]