2012-07-02 15 views
0

在我的应用程序中,我有一个复杂的数据库结构。为了为一个调用生成JSON响应,我需要从许多连接的表中获取数据。如何避免再次调用数据库当我已经拥有全部需要的SQL调用结果时

我创建了一个SQL查询,获取我需要的所有数据(使用rails'includes)。然而,现在我认为我的结果是,我无法弄清楚什么是实际呈现它的正确方法。

一个简单的例子,不是我的实际代码:比方说,我有项目包含子项目包含任务和查询返回他们所有的一些嵌套结构,根据一些过滤逻辑。

class Project < ActiveRecord::Base 
    ... 
    def with_sub_projects_visible_by(user) 
    includes(...complex join with sub projects and tasks...) 
    .where(...complex condition...) 
    end 
end 

在控制器我有这样的事情:

def show 
    @project_with_full_details = Project.find(params[:id]).with_sub_projects_visible_by(current_user) 
    end 

有没有写,这将使得包含从@project_with_full_details的所有数据,而无需再次调用数据库中的页面简洁视图代码的方法吗?从我的尝试中,只需拨打@project_with_full_details.sub_projects并不能解决问题。它调用数据库并获取相关子项目的完整列表,而不是应该包含在查询结果中的已过滤列表。

(我使用Rabl的对我的看法,因为我渲染JSON,但它是那么重要,ERB例如将完全罚款)

+0

只是在执行'includes(:tasks)'应该为您做好急切的加载并且只做一个连接查询来获取对象和相关的任务关联。 '包括(...复杂的加入子项目和任务...)'不会最大限度地发挥作用,如果你想用自定义查询做一个非常复杂的连接,你需要'join()'方法 – VelLes

回答

1

的ActiveRecord提供了一个预加载了导致的Rails只加载的关联来自数据库的对象一次(它也发生在页面加载之前)。

对于你的榜样,它可能会是这个样子:

@project = Project.find(params[:id]) 
ActiveRecord::Associations::Preloader.new(
    @project, [ :subprojects, subprojects: :tasks] 
) 

这将至少给你只能在运行SQL一旦预期的效果。

如果你的模型看起来是这样的:

class Project 
    has_many :users 
    has_many :sub_projects 
    has_many :tasks, through: :sub_projects 
    ... 
end 

那么也许你可以这样定义subprojects_for(user)的方法。那么你应该可以沿着这些线做些事情:

# controller 
@project = Project.find(params[:id]) 
@subprojects = @project.subprojects_for(current_user) 

# haml 
.project 
    = @project.title 
    - @project.subprojects_for(current_user).each do |subproject| 
    = Something for subprojects... 
    - subproject.tasks.each do |task| 
     = You get the idea 

虽然真正的魔法应该发生在preloader中。我假设你已经查看了服务器日志,看到SQL正在运行多次?

+0

谢谢快速回答。我确实查看了服务器日志,发现SQL正在运行多次。我尝试了类似这种方法,但我的问题是,subprojects_for(like)方法在我的情况下非常复杂,并转到数据库。你使用预加载器会如何显示,导致它在内存中运行? – davidrac

+0

如果不知道'with_sub_projects_visible_by'需要做什么,很难说。大概你有'User','Subproject'和'SubprojectPermission'模型,或者这些模型?你能不能做一些像SubprojectPermission.where(user:4).map(&:subproject)'? –

+0

编号计算子子程序的权限涉及到一些复杂的逻辑:检查谁是拥有它的用户,以及她与当前用户的关系。它涉及更多的数据库表。这就是为什么我最初认为将该逻辑作为模型的一部分并将计算结果返回到视图是一个好主意...... – davidrac

相关问题