16

class User  
  has_many :tickets 
end

ユーザーのカウントチケットのロジックを含む関連付けを作成し、インクルードで使用したい (user has_one ticket_count)

Users.includes(:tickets_count)

私は試した

  has_one :tickets_count, :select => "COUNT(*) as tickets_count,tickets.user_id " ,:class_name => 'Ticket', :group => "tickets.user_id", :readonly => true  

User.includes(:tickets_count)

 ArgumentError: Unknown key: group

この場合、インクルードの関連付けクエリは、count を group by で使用する必要があります ... Rails を使用してこれを実装するにはどうすればよいですか?

アップデート

  • テーブル構造を変更できない
  • インクルードを持つユーザーのコレクションに対して AR が 1 クエリを生成するようにしたい

Update2

私はSQLを知っており、これを結合で選択する方法を知っていますが、私の質問は「データを取得する方法」のようなものです。私の質問は、インクルードで使用できる関連付けの構築についてです。ありがとう

Update3 ユーザー has_one ticket_count のように作成したアソシエーションを作成しようとしましたが、

  1. has_one は関連拡張機能をサポートしていないようです
  2. has_one は :group オプションをサポートしていません
  3. has_one は finder_sql をサポートしていません
4

4 に答える 4

16

これを試して:

class User

  has_one :tickets_count, :class_name => 'Ticket', 
    :select => "user_id, tickets_count",
    :finder_sql =>   '
        SELECT b.user_id, COUNT(*) tickets_count
        FROM   tickets b
        WHERE  b.user_id = #{id}
        GROUP BY b.user_id
     '
end

編集:

関連付けがオプションhas_oneをサポートしていないようです。finder_sql

scope/classメソッドの組み合わせを使用することにより、あなたが望むことを簡単に達成することができます

class User < ActiveRecord::Base

  def self.include_ticket_counts
    joins(
     %{
       LEFT OUTER JOIN (
         SELECT b.user_id, COUNT(*) tickets_count
         FROM   tickets b
         GROUP BY b.user_id
       ) a ON a.user_id = users.id
     }
    ).select("users.*, COALESCE(a.tickets_count, 0) AS tickets_count")
  end    
end

User.include_ticket_counts.where(:id => [1,2,3]).each do |user|
  p user.tickets_count 
end

テーブルに数百万の行がある場合、このソリューションはパフォーマンスに影響しticketsます。WHERE内部クエリに提供することにより、JOIN結果セットのフィルタリングを検討する必要があります。

于 2012-02-21T03:14:32.360 に答える
10

特定のユーザーに対して簡単に使用できます。

user.tickets.count

または、この値を Rails によって自動的にキャッシュしたい場合。

関連付けの反対側で counter_cache => true オプションを宣言します

class ticket
  belongs_to :user, :counter_cache => true
end

また、ユーザー テーブルに ticket_count という名前の列も必要です。これにより、ユーザーレールに新しいチケットを追加するたびにこの列が更新されるため、ユーザーレコードを取得するときに、この列にアクセスするだけで、追加のクエリなしでチケット数を取得できます。

于 2012-02-09T11:04:12.963 に答える
7

きれいではありませんが、機能します:

users = User.joins("LEFT JOIN tickets ON users.id = tickets.user_id").select("users.*, count(tickets.id) as ticket_count").group("users.id")
users.first.ticket_count
于 2012-02-13T21:23:28.393 に答える
0

クエリを実行する User モデルにメソッドを追加するのはどうですか?

テーブル構造を変更することはありませんか、それとも変更できませんか?

于 2012-02-19T22:32:28.527 に答える