我在使用Rails 3.0.9的项目上使用postgres tsearch。要进行tsearch查询,我需要在“from”子句中包含额外的SQL。例如,假设我有这个模型:
class User < ActiveRecord::Base
has_one :profile
has_many :memberships
has_many :groups, :through => :memberships
end
我想对用户及其个人资料进行全文搜索。我可以这样做:
User.joins(:profile).where(
"(profiles.vectors @@ tsearch_query) or (users.vectors @@ tsearch_query)"
).from(
"to_tsquery('MYQUERY') as tsearch_query, users")
这会产生以下SQL,它可以正常工作:
"SELECT \"users\".* FROM to_tsquery('MYQUERY') as tsearch_query, users INNER JOIN \"profiles\" ON \"profiles\".\"user_id\" = \"users\".\"id\" WHERE ((profiles.vectors @@ tsearch_query) or (users.vectors @@ tsearch_query))"
但如果我加入另一个连接,我会得到一些不好的SQL:
User.joins(:profile).where(
"(profiles.vectors @@ tsearch_query) or (users.vectors @@ tsearch_query)"
).from(
"to_tsquery('MYQUERY') as tsearch_query, users").joins(:groups)
这是错误:
ActiveRecord::StatementInvalid: PGError: ERROR: missing FROM-clause entry for table "memberships" at character 108
: SELECT "users".* FROM to_tsquery('MYQUERY') as tsearch_query, users INNER JOIN "groups" ON "groups"."id" = "memberships"."group_id" WHERE AND ((profiles.vectors @@ tsearch_query) or (users.vectors @@ tsearch_query))
此查询中应该有三个连接语句。用户到个人资料,用户到成员资格和成员资格到群组。仅包含最后一个连接,因此我们在引用成员资格表时遇到错误而没有先加入它。
但AR :: Relation确实知道两个连接:
irb(main)> _.send(:joins_values)
=> [:profile, :groups]
我认为问题在于添加“来自”范围调用。如果我把它剪掉,我会得到两个连接。例如,我甚至可以提供一个虚拟的“来自”调用并得到相同的错误:
User.joins(:profile).from( "users" ).joins(:groups)
ActiveRecord::StatementInvalid: PGError: ERROR: missing FROM-clause entry for table "memberships" at character 68
: SELECT "users".* FROM users INNER JOIN "groups" ON "groups"."id" = "memberships"."group_id"
irb(main)> _.send(:joins_values)
=> [:profile, :groups]
删除“来自”呼叫,这很好用:
User.joins(:profile).joins(:groups)
irb(main)> _.to_sql
=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"profiles\" ON \"profiles\".\"user_id\" = \"users\".\"id\" INNER JOIN \"memberships\" ON \"users\".\"id\" = \"memberships\".\"user_id\" INNER JOIN \"groups\" ON \"groups\".\"id\" = \"memberships\".\"group_id\"
所以我不确定如何解决这个问题。
我的最终目标是能够对用户及其个人资料进行搜索搜索,同时还限制用户所在群组的搜索结果。
答案 0 :(得分:1)
FWIW,这不是一个很好的答案,但是一个体面的解决方法:我可以通过将连接的实际SQL传递给User.joins而不是使用关系名来实现这一点。可能现在必须做。
与此同时,我想我会整理一份错误报告。
答案 1 :(得分:1)
另一个不太好的解决方案是等待rails 3.1。
将此测试添加到activerecord的inner_join_association_test.rb中:
def test_from_clause_clobbers_multiple_joins
result = Author.joins(:posts).from('authors').joins(:categorizations).where(:categorizations => {:id => 1}, :posts => {:id => 1}).to_a
assert_equal authors(:david), result.first
end
在3.0.9上失败,但在3.1-rc1上传递