2011-06-27 3 views
2

Rails 3.0.9のプロジェクトでpostgres tsearchを使用しています。 tsearchクエリを作成するには、 "from"句に余分なSQLを含める必要があります。たとえば、次のモデルがあるとします。ActiveRecord :: QueryMethods#from joinは悪い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").joins(: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))" 

しかし、私は他の上タック場合、私はいくつかの悪いSQLを取得する加入:これは、次のSQLを生成し、それが正常に動作します

User.joins(:profile).where(
    "(profiles.vectors @@ tsearch_query) or (users.vectors @@ tsearch_query)" 
).from(
    "to_tsquery('MYQUERY') as tsearch_query, users") 

:私はこれを行うことができますエラー:

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)) 

There's sこのクエリでは3つのjoin文が必要です。ユーザー対プロファイル、ユーザー対メンバーシップ、およびメンバーシップからグループへのアクセスを管理します。最後の結合だけが含まれているので、以前に結合せずにメンバーシップテーブルを参照する際にエラーが発生します。

しかし、AR ::関係は知っているん両方の加入:

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\" 

は、だから私はよく分からない例えば、私も同じエラーをコール「から」ダミーを提供して取得することができますこれを回避する方法。

もユーザがあるグループで結果を制限しながら、私の最終的な目標は、ユーザーとそのプロファイルにtsearch検索を行うことができるようにすることです。

+0

注意の上を通過するが、これは/ワットだけの問題ではありません。コード: 'User.joins(:プロファイル).from( "ユーザー").joins(:メンバーシップ)' SQL: 'SELECT \ "ユーザ\" * INNERは\ JOINのユーザーからの "メンバーシップを\"。 \ "ユーザーID \" = \ "ユーザー\" \ "ユーザーID \" どのように参加してください:プロファイルが見つかりません – Miriam

+0

私は尋ねるが、 ?私はルビーには新しく、それを試していないが、私が言うことができる限り、Sequelの作者はポストグル・ジャンキーであり、これを使って失敗するのではないかと疑う。SequelはDBごとに異なるドライバを持っている。 ActiveRecordは対照的に(とにかく私はそれを見たのが一番です)、クロスDBクエリをフル実装しようとしています。これは、DB特有の機能を使用するときに、ある時点または別の時点で失敗することが多かれ少なかれ保証されます。 –

+0

@デニス、私は続編のことを聞いていない。残念なことに、これはレール2のアプリケーションからのポートです。したがって、私たちはActiverecordにかなり献身しています。私は将来のプロジェクトのためにそれを念頭に置いています。 – Miriam

答えて

1

FWIW、これは偉大な答えはありませんが、適切な回避策:リレーション名を使用するのではなく、結合の実際のSQLをUser.joinsに渡すことで、これを機能させることができます。今のところやる必要があるかもしれません。

その間、私はバグ報告をまとめることにします。

1

もう一つの大きな解決策は、レール3.1を待つことです。

追加のActiveRecordのinner_join_association_test.rbに、このテスト:has_many_through関係:

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の

関連する問題