2014-12-29 6 views
0

ActiveRecord가 잘못된 쿼리를 생성하는 것으로 보이는 문제가 있습니다. 컨트롤러 반면 owner_organisation에 가입 모델이을 포함ActiveRecord/arel에서 조인()을 사용할 때 대체 연관 이름을 지정할 수 있습니까?

class Licence < ActiveRecord::Base 
    belongs_to :organisation 
    belongs_to :owner_organisation, :class_name => 'Organisation' 
    # omitting other relationships 

    def self.search(params = {}) 
    collection = self 
    table = self.arel_table 

    # omitting filtering of the collection 

    case params[:order] 

     # these two work: 
     when 'generated_by' 
     collection = collection.joins(:organisation). 
           order('organisations.name ASC') 
     when 'generated_by_reverse' 
     collection = collection.joins(:organisation). 
           order('organisations.name DESC') 

     # these two cause the problem: 
     when 'owner' 
     collection = collection.joins(:owner_organisation). 
           order('owner_organisations.name ASC') 
     when 'owner_reverse' 
     collection = collection.joins(:owner_organisation). 
           order('owner_organisations.name DESC') 
           # ^- this order() is almost certainly wrong too, but I 
           # will fix that once I get a table name I can predict... 

     # omitting other orderings 
    end 

    collection 
    end 

end 

class LicencesController < ApplicationController 

    def index 
    @licences = Licence.search(params). 
     includes(:organisation, :user, :owner_organisation, :profile) 
    end 

end 

당신은 알 수 있습니다 : 여기

는 컨트롤러를 사용하는 모델의 본질과 방법이다. 이것은 문제의 일부인 것처럼 보입니다.

이로 인해 이상한 쿼리가 만들어지고 오류가 발생합니다.

ActionView::Template::Error: SQLite3::SQLException: no such column: owner_organisations_licences.id: 

그리고 실제로 쿼리가이 이름을 가진 테이블을 포함하지 않는

는 (열이 선택되는 많은에게 있기 때문에 나는 쿼리를 줄일.)

SELECT 
    "licences"."id" AS t0_r0,   # omitting rest of the columns for all these 
    "organisations"."id" AS t1_r0, 
    "users"."id" AS t2_r0, 
    "dongles"."id" AS t3_r0, 
    "owner_organisations_licences"."id" AS t4_r0,  # this is the problem 
    "profiles"."id" AS t5_r0 
FROM "licences" 
    INNER JOIN "organisations" 
    ON "organisations"."id" = "licences"."owner_organisation_id" 
    LEFT OUTER JOIN "organisations" "organisations_licences" 
    ON "organisations_licences"."id" = "licences"."organisation_id" 
    LEFT OUTER JOIN "users" 
    ON "users"."id" = "licences"."user_id" 
    LEFT OUTER JOIN "dongles" 
    ON "dongles"."id" = "licences"."dongle_id" 
    LEFT OUTER JOIN "profiles" 
    ON "profiles"."id" = "licences"."profile_id" 
WHERE "licences"."parent_licence_id" IS NULL 
ORDER BY owner_organisations.name ASC 
LIMIT 50 OFFSET 0 

내가 볼 수있는 여기에 내 includes(:organisations)organisations_licences이되는 이름 지정 체계가 있습니다. 그러나 owner_organisation은 이미 joins(:owner_organisation)과 함께 사용되었으므로 INNER JOIN으로 삽입되었습니다. 이유가 무엇이든간에 #joins#includes과 동일한 규칙을 따르지 않으므로 "잘못된"이름이 적용됩니다. 그러나 어떤 이유로 든 무엇을 선택할지 지정할 때 owner_organisations_licences을 사용하므로 쿼리가 유효하지 않습니다.

내가 조인 된 테이블에 어떤 이름을 알려주는 지 알아낼 수 있다면이 문제를 피할 수 있을지 모르겠다.하지만 어떻게해야하는지 알 수 없다.

방법이 있습니까?

답변

1

includes은 항상 데이터베이스 수준에서 JOIN을 수행 할 것으로 예상 할 수 없습니다. 실제로 include에는 두 가지 전략이 있으며 JOIN을 사용할 수도 있고 두 번째 쿼리를 실행할 수도 있습니다 (일반적인 N + 1 문제보다 더 빨리 해결할 수있는 문제가 includes). includes works에 대한 자세한 내용은 article입니다.

문제의 해답 : joinsincludes을 같은 테이블에 동시에 사용하지 마십시오. 나는 그 실제 문제가 알아 낸 후 (이 수정 포함하지 않는 것으로 가정 호출됩니다 어떤 순서()의 질문에 대한 대답 추측

case params[:order] 
when 'generated_by' 
    collection = collection.includes(:organisation). 
          order('organisations.name ASC'). 
          references(:organisations) 
when 'generated_by_reverse' 
    collection = collection.includes(:organisation). 
          order('organisations.name DESC'). 
          references(:organisations) 
when 'owner' 
    collection = collection.includes(:owner_organisation). 
          order('organisations.name ASC'). 
          references(:organisations) 
when 'owner_reverse' 
    collection = collection.includes(:owner_organisation). 
          order('organisations.name DESC'). 
          references(:organisations) 
end 
+0

: 레일 4에서이 문제를 해결하는 새로운 방법 references있다 그 테이블/협회의 이름). 그러나 그것은 실제로 질문 자체에 대답하지 않습니다. – Trejkaz

+0

@Trejkaz : 답변을 업데이트합니다. – spickermann

+0

그 기사는 preload()를 사용하여 Rails가 조인을 사용하는 것을 피할 수 있다고 말하는 점에서 실제로 좋은 팁을 가지고 있습니다. 변경하면 확실히 문제가 중지되지만 (예기치 않은 성능 저하가 발생할 수 있습니다.) 현재로서는이 페이지가 복잡하기 때문에 단일 쿼리로 실행됩니다. 참조는 좋지만 참고 만해도 좋을 것 같습니다. 먼저 Rails 4로 업그레이드하십시오. 어쨌든 그렇게하고 싶었 기 때문에 고려 중입니다. – Trejkaz