我正处于ActiveRecord似乎生成无效查询的问题上。
以下是模型的本质以及控制器如何使用它:
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
您会注意到模型加入 owner_organisation,而控制器包含它。这似乎是问题的一部分。
这会导致创建一个奇怪的查询,但我收到错误。
ActionView::Template::Error: SQLite3::SQLException: no such column: owner_organisations_licences.id:
实际上查询并没有包含具有此名称的表:(我删除了查询,因为选择了 lot 列。)
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
,所以它有&#34;错误&#34;名称。但是,无论出于何种原因,当它指定要选择的内容时,它会使用{{1}},因此查询无效。
我想我可以解决这个问题,如果有办法告诉arel什么名字给连接表,但我无法弄清楚如何做到这一点。
有办法吗?
答案 0 :(得分:1)
您不能指望includes
始终在数据库级别执行JOIN
。实际上include
有两种不同的策略,它可能会使用JOIN
,或者它可能会触发第二个查询(仍然比常见的N + 1问题includes
尝试解决的速度更快)。您可能对此article感兴趣includes works
。
问题的答案:不要在同一张桌子上同时使用joins
和includes
。在Rails 4中,有一种新方法references
可以解决这个问题:
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