2012-07-02 1 views
0

복잡한 데이터베이스 구조를 가지고 있습니다. 호출에 대한 JSON 응답을 생성하려면 여러 조인 된 테이블에서 데이터를 가져와야합니다.SQL 호출의 결과로 필요한 모든 것을 이미 가지고있을 때 데이터베이스를 다시 호출하는 것을 피하는 방법

필요한 모든 데이터를 가져 오는 SQL 쿼리를 만들었습니다 (레일 '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으로 전화하는 것은 그 속임수를 쓰지 않습니다. 데이터베이스를 호출하고 쿼리 결과에 포함되어야하는 필터링 된 서브 프로젝트 대신 관련된 sub_project 전체 목록을 가져옵니다.

+0

단지'includes (: tasks)'를 수행하는 것은 당신을 위해 열심히로드해야하고 객체와 관련 작업 연관을 얻기 위해 하나의 조인 쿼리 만 만들어야합니다. '포함 (... 하위 프로젝트와 작업과의 복잡한 결합) ...''가장 마음에 들지 않습니다. 사용자 정의 쿼리로 매우 복잡한 결합을 원한다면, join() 메소드가 필요합니다. – VelLes

답변

1

액티브는 레일 만로드됩니다 협회의 프리 로더를 제공한다 (ERB 예 완전히 잘 될 것입니다 내가 JSON을 렌더링하고있어 이후, 내보기에 대해 RABL를 사용하고 있지만, 덜 중요) 데이터베이스에서 개체를 한 번 (페이지가로드되기 전에 발생합니다).

@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 

진짜 마법

하지만, 프리 로더에서 일어난 있어야합니다. 나는 당신이 서버 로그를보고 SQL이 두 번 이상 실행되고 있음을 확인했다고 가정한다.

+0

고맙습니다 빠른 대답. 나는 서버 로그를보고 SQL이 두 번 이상 실행되고 있음을 확인했다. 이 접근법과 비슷한 것을 시도했지만, 내 문제는 subprojects_for (같은) 메서드가 내 경우에 상당히 복잡하고 데이터베이스로 이동한다는 것입니다. 당신이 보여준 것처럼 프리 로더를 사용하면 메모리에이 문제가 발생합니까? – davidrac

+0

'with_sub_projects_visible_by'가해야 할 일을 모른 채로 말하기는 어렵습니다.아마도'User'','Subproject','SubprojectPermission' 모델을 가지고 있을까요? 'SubprojectPermission.where (user : 4) .map (& : subproject)'와 같은 것을 할 수 있을까요? –

+0

subproejcts에 대한 사용 권한을 계산하는 것은 복잡한 논리를 포함합니다. 누가 소유 한 사용자인지와 현재 사용자와의 관계를 확인하는 것입니다. 더 많은 데이터베이스 테이블이 필요합니다. 그래서 처음에는 모델의 일부로 그 논리를 가지고 계산 결과를보기에만 반환하는 것이 좋을 것이라고 생각한 이유입니다 ... – davidrac

관련 문제