Rails 在索引上预先加载自定义 has_many
Rails eager load custom has_many on index
Ruby2.1,Rails3.2
我的项目模型中有这种关系
scope :active, -> { where( deleted_at: nil ) }
has_many :foremen, class_name: "ProjectsUser", conditions: ['current_foreman = 1']
在控制器中:
@projects = Project.includes(:foremen).active
生成此 SQL
ProjectsUser Load (3.3ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` IN (122, 130, ...etc.) AND ( current_foreman = 1)
但是当我调用视图中的关系时...
<% @projects.each do |project| %>
<%= project.foremen.current_foreman %>
<% end %>
它每次运行另一个 SQL 查询。
ProjectsUser Load (2.5ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` = 122 AND (current_foreman = 1 )
ProjectsUser Load (2.5ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` = 130 AND (current_foreman = 1 )
ProjectsUser Load (2.5ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` = 151 AND (current_foreman = 1 )
etc...
我是不是误会了什么?这些记录不应该已经加载了吗?
我该如何编写它以便它只运行一个查询 ProjectsUser
?
我认为您在项目循环内调用它是正常的。
所以我做了更多的挖掘,发现我的逻辑是正确的;这不会自行生成任何其他查询。问题是我在对象上调用的方法。
以下不调用任何查询:
project.current_foremen_and_managers.select{|f| f.current_foreman}.sort_by{ |f| f.added_at}.first
但是,当您将额外的逻辑移动到关联的 class 中的方法时,它确实会生成更多 sql
class ProjectUser < ActiveRecord::Base
def self.find_first_foreman
select{|f| f.current_foreman}.sort_by{ |f| f.added_at}.first
end
end
然后,如果我调用此方法,它会运行一个查询
project.current_foremen_and_managers.find_first_foreman
我不完全确定为什么会发生这种情况,如果有人有解释,我很想听听。
Ruby2.1,Rails3.2
我的项目模型中有这种关系
scope :active, -> { where( deleted_at: nil ) }
has_many :foremen, class_name: "ProjectsUser", conditions: ['current_foreman = 1']
在控制器中:
@projects = Project.includes(:foremen).active
生成此 SQL
ProjectsUser Load (3.3ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` IN (122, 130, ...etc.) AND ( current_foreman = 1)
但是当我调用视图中的关系时...
<% @projects.each do |project| %>
<%= project.foremen.current_foreman %>
<% end %>
它每次运行另一个 SQL 查询。
ProjectsUser Load (2.5ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` = 122 AND (current_foreman = 1 )
ProjectsUser Load (2.5ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` = 130 AND (current_foreman = 1 )
ProjectsUser Load (2.5ms) SELECT `projects_users`.* FROM `projects_users` WHERE `projects_users`.`project_id` = 151 AND (current_foreman = 1 )
etc...
我是不是误会了什么?这些记录不应该已经加载了吗?
我该如何编写它以便它只运行一个查询 ProjectsUser
?
我认为您在项目循环内调用它是正常的。
所以我做了更多的挖掘,发现我的逻辑是正确的;这不会自行生成任何其他查询。问题是我在对象上调用的方法。
以下不调用任何查询:
project.current_foremen_and_managers.select{|f| f.current_foreman}.sort_by{ |f| f.added_at}.first
但是,当您将额外的逻辑移动到关联的 class 中的方法时,它确实会生成更多 sql
class ProjectUser < ActiveRecord::Base
def self.find_first_foreman
select{|f| f.current_foreman}.sort_by{ |f| f.added_at}.first
end
end
然后,如果我调用此方法,它会运行一个查询
project.current_foremen_and_managers.find_first_foreman
我不完全确定为什么会发生这种情况,如果有人有解释,我很想听听。