在我的Rails应用中,我people
可以有很多projects
,反之亦然。这两个表由连接表jobs
链接。
class Project < ActiveRecord::Base
belongs_to :user
has_many :people, :through => :jobs
def self.names_as_options
order(:name).map{ |p| [ p.name, p.id, :'data-people_count' => p.people.count ] }
end
end
在我的一个表格中,我有这个选择框:
<%= f.select :project_id, Project.names_as_options %>
问题是count
上的people
为每个项目提供了 N + 1 查询。
克服这个问题的最佳方法是什么?
感谢您的帮助。
答案 0 :(得分:1)
尝试使用范围与lambda,为此,这是一个如何工作的例子:
scope :top, lambda { order('views DESC').limit(20) }
在控制器中调用
Project.top
这是在Ruby on Rails中过滤结果的最佳方法。
答案 1 :(得分:1)
如果您使用计数,您最好也使用计数器缓存,它们会在需要时自动使用。 http://guides.rubyonrails.org/association_basics.html
答案 2 :(得分:1)
您可以添加&#34;计数器缓存&#34;每个项目的人数。通常,您将通过迁移
向项目表中添加一个字段add_column :projects, :people_count, :integer, :default => 0
然后声明在Person模型中使用:counter_cache
class Person < ActiveRecord::Base
belongs_to :projects, :counter_cache => true
end
当你正在进行求职加入时,这可能不会做你想要的事情。所以,Person #project声明只是一个方便的查找器,并没有在任何回调中使用。但是,你明白了。
您可以按照上面的建议添加一个列,然后在Job类中使用一些回调方法。
class Job
def update_project_counter
project.update_people_counter
end
after_create :update_project_counter
after_destroy :update_project_counter
end
class Project
def update_people_counter
self.update_attribute :people_count, people.count
end
end
或类似的东西。那么您应该只需要一个查询。
class Project < ActiveRecord::Base
def self.names_as_options
order(:name).map do |p|
[p.name, p.id, :'data-people_count' => p.people_count]
end
end
end
答案 3 :(得分:1)
急切加载将解决此问题,请使用“包含”如下。
实施例,
class LineItem < ActiveRecord::Base
belongs_to :order, -> { includes :customer }
end
class Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class Customer < ActiveRecord::Base
has_many :orders
end