2

ARクエリ構造と完全に連携するかなり単純なクエリがあります。

user = User.includes({:network => :product}).joins({:network => :product}).where(:id => user_id).first

これにより、データベースに対して単一のクエリが実行され、熱心にロードされたコレクションにデータが入力されます(つまりuser.product.network.name、DBに追加のクエリを呼び出さなくても呼び出すことができます)。

Userユーザーのテーブルに存在しないオブジェクトにいくつかの「疑似」列を追加したいのですが、この最初のクエリの一部としてデータを入力したいと思います。SQLは次のようになります。

SELECT 
    "users".*,
    "networks".*,
    "products".*, 
    (select count("spaces".id) from spaces "spaces" where "spaces".owner_id = "users".id) as spaces_count
FROM
    users "users" 
JOIN
    networks "networks" 
    on "networks".id = "users".network_id 
JOIN products "products" 
    on "products".id="networks".product_id 
WHERE "users".id=?

(最適化されていない)内部クエリでの「spaces_count」列の追加は、この段階での唯一の「pseduo」列ですが、ビューはさらに追加することです。

Userクラス(ActiveRecordモデル)には次のものがあります。

attr_accessible :spaces_count

SQLクエリを実行するために、以下を使用しています。

user = find_by_sql(sql)
ActiveRecord::Associations::Preloader.new([user], {:network => :product}).run

ここで、sqlは上記に含まれるクエリです。

結果は、 「疑似」列Userを含む、予想どおりに入力されたモデルですが、アソシエーションプリローダーの呼び出しの一部として、DBにさらに2回ヒットします。spaces_countrun

1.9.3p125 :465 > ActiveRecord::Associations::Preloader.new([user], {:network => :product}).run
  Network Load (0.5ms)  SELECT "networks".* FROM "networks" WHERE "networks"."id" IN (1)
  Product Load (0.3ms)  SELECT "products".* FROM "products" WHERE "products"."id" IN (1)
=> [{:network=>:product}] 

ActiveRecord::Associations::Preloaderのように、DBに追加の回数ヒットすることなく、関連付けを熱心にフェッチするために使用する方法はありincludesますjoinsか?

Rails 3.2、Ruby 1.9.3-p125、PG9.1を使用しています。

4

1 に答える 1

1

あなたが求めることを正確に行う方法があるかどうかはわかりません。あなたがそうする必要はないことを私は知っています-それらのARの「クエリ構造」をもっと使用するだけです。

まず、カスタム選択を指定できます。

users = User.includes({:network => :project}).select('users.*, (select count("spaces".id) from spaces "spaces" where "spaces".owner_id = "users".id) as spaces_count').joins({:network => :product}).where(:id => user_id).first

これらは任意の順序で取り組むことができます。私の個人的な慣習では、「includes」が最初に来て、次にクエリに表示される順序で他のすべてが来るというものですが、それは私だけです。これでも、必要な積極的な読み込みが可能になり、返されたオブジェクトで名前を呼び出すことで、「疑似列」の値を取得できます。

users.first.spaces_count

注意:PostgreSQLアダプタは、データベース内の実際のタイプに関係なく、これらの値を文字列として返すように見えるため、後で変換する必要がある場合があります。

users.first.spaces_count.to_i

最後に、このソリューションがあなたに役立つことを願っていますが、あなたが提案する方法についての回答にも興味があります-AR :: Associations::Preloaderを介したカスタマイズされた熱心な読み込みはクールで便利に聞こえます。

于 2012-10-10T15:18:15.693 に答える