0

簡単な例として、書店に著者が 1 人の本があるとします。書籍は受注販売が多い。著者は多くの本を持つことができます。

売り上げ順に著者をリストする方法を探しています。販売は著者ではなく書籍に関連付けられているため、どうすればこれを達成できますか?

私は次のように推測します: Author.order("sales.count").joins(:orders => :sales)

しかし、それは列が見つからないというエラーを返します。

Author モデルで定義することで、それらを接続することができました。以下は、売上の正しいカウントを表示しますが、すべての作成者に対してデータベースに ping を実行します...まずいです。私はむしろ熱心にロードしたいと思っていますが、self.id を削除して @authors に結合を割り当てると、たまたま売上が 0 の著者がリストされないため、適切に機能するようには見えません。

    class Author < ActiveRecord::Base

      def sales_count
        Author.where(id: self.id).joins(:orders => :sales).count
      end
    end

より具体的には、最も人気のある著者を最初にリストできるように、カウント結果でそれらを並べ替えるにはどうすればよいですか?

4

1 に答える 1

2

まず、クエリ コードをシンプルに保つために、すべての関連付けを Author クラス自体で使用できるようにします。

class Author < AR::Base
  has_many :books
  has_many :orders, :through => :books
  has_many :sales, :through => :orders
end

最も簡単な方法は、 groupwithを使用するcountことです。これにより、次の形式でハッシュが取得されます{author-id: count}

author_counts = Author.joins(:sales).group("authors.id").count
=> {1 => 3, 2 => 5, ... }

author_counts作成者をソートし、ハッシュを使用してカウントを検索できるようになりました(売り上げのない作成者は を返しnilます)。

<% Author.all.sort_by{|a| author_counts[a.id] || 0}.reverse.each do |author| %>
  <%= author.name %>: <%= author_counts[author.id] || 0 %>
<% end %>

アップデート

別のアプローチは、LEFT JOIN を生成するために使用する制限を回避できるar_outer_joins gem を使用することです。includes

authors = Author.outer_joins(:sales).
                 group(Author.column_names.map{|c| "authors.#{c}").
                 select("authors.*, COUNT(sales.id) as sales_count").
                 order("COUNT(sales.id) DESC")

これで、ビューは次のようになります。

<% authors.each do |author| %>
  <%= author.name %>: <%= author.sales_count %>
<% end %>

この例は、LEFT JOIN が、他の関連付けを熱心にロードできない (または特に望んでいない) 場合にいかに役立つかを示しています。outer_joinsデフォルトで ActiveRecord に含まれていない理由がわかりません。

于 2013-04-28T05:01:56.693 に答える