Ruby on rails 3 将ActiveRecord::QueryMethodsfrom与联接链接在一起会产生错误的SQL和缺少的联接

Ruby on rails 3 将ActiveRecord::QueryMethodsfrom与联接链接在一起会产生错误的SQL和缺少的联接,ruby-on-rails-3,postgresql,full-text-search,Ruby On Rails 3,Postgresql,Full Text Search,我在一个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 这将生成以下SQL,并且工作正常: "SELECT \"users\".

我在一个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
这将生成以下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))"
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\"
但是如果我添加了另一个连接,我会得到一些糟糕的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))
此查询中应该有三个join语句。用户到配置文件、用户到成员身份以及用户到组的成员身份。只包括最后一个联接,因此我们在引用memberships表时会出现一个错误,而不在前面联接它

但是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]
从调用中删除,这可以正常工作:

"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))"
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\"
所以我不知道如何解决这个问题


我的最终目标是能够对用户及其配置文件进行tsearch搜索,同时根据用户所在的组限制搜索结果。

FWIW,这不是一个很好的答案,但却是一个不错的解决办法:我可以通过将连接的实际SQL传递给User.joins,而不是使用关系名称来实现这一点。也许现在该做了


同时,我想我会编写一份bug报告。

另一个不太好的解决方案是等待rails 3.1

将此测试添加到activerecord的内部加入协会测试.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上通过。注意,这不仅仅是一个关系问题。代码:User.joins:profile.from users.joins:memberships sql:SELECT\users\.*from users internal JOIN\memberships\ON\memberships\。\User\u id\=\users\。\id\注意:配置文件上的加入是如何丢失的我不想问,但是。。。你考虑过续集吗?我是ruby新手,还没有尝试过,但据我所知,Sequel的作者是一个博士后迷,我怀疑使用它会失败。。。Sequel每分贝有一个不同的驱动程序。相比之下,我所看到的ActiveRecord试图实现跨数据库查询的完整功能。当您使用DB特定的功能时,这或多或少保证会失败。@Denis,我没听说过Sequel。不幸的是,这是rails 2.*应用程序的一个端口,所以我们非常支持Activerecord。不过,我会在未来的项目中牢记这一点。是的,我的理解是,有一个包装器可以让续集说成是活动记录,作为替换。在我脑海中搜索一个名为sequel rails或sequel activerecord的宝石。