2016-04-30 10 views
0

imagesの数を表示する方法を探しています。categoryがあり、has_manyの関連付けで取得しました。私は、実装上counter_cacheにはほとんどなく、まだありません喜びを読んでてきた関連するオブジェクトを数える効率的な方法 - Rails 4

class Category < ActiveRecord::Base 
    has_many :image_categories 
    has_many :images, through: :image_categories 
end 

class ImageCategory < ActiveRecord::Base 
    # Holds image_id and category_id to allow multiple categories to be saved per image, as opposed to storing an array of objects in one DB column 
    belongs_to :image 
    belongs_to :category 
end 

class Image < ActiveRecord::Base 
    # Categories 
    has_many :image_categories, dependent: :destroy 
    has_many :categories, through: :image_categories 
end 

コントローラ

@categories = Category.all 

ビュー

<% @categories.each do |c| %> 
    <li> 
    <%= link_to '#', data: { :filter => '.' + c.name.delete(' ') } do %> 
     <%= c.name %> (<%= #count here %>) 
    <% end %> 
    </li> 
<% end %> 

誰もがそれをいただければ幸い助けることができれば

ありがとう

答えて

2

あなたが効率的な方法を探しているので同じように、私はあなたのモデルがはずれている方法をここでcounter_cache

を使用することをお勧めします:あなたはあなたのcategoriesテーブルとcategory_countimage_countフィールドを追加する必要があります

class Category < ActiveRecord::Base 
    has_many :image_categories 
    has_many :images, through: :image_categories 
end 

class ImageCategory < ActiveRecord::Base 
    # Holds image_id and category_id to allow multiple categories to be saved per image, as opposed to storing an array of objects in one DB column 
    belongs_to :image, counter_cache: :category_count 
    belongs_to :category, counter_cache: :image_count 
end 

class Image < ActiveRecord::Base 
    # Categories 
    has_many :image_categories, dependent: :destroy 
    has_many :categories, through: :image_categories 
end 

imagesのテーブル。

カウンタとフィールドの追加が完了したら、カウンタがリセットされ、フィールドがデータベースに既に存在するレコードの正しいカウント値で更新されるようにする必要があります。

Category.find_each { |category| Category.reset_counters(category.id, :images) } 

Image.find_each { |image| Image.reset_counters(image.id, :categories) } 
+0

ありがとうございました。実装方法についてのご意見はありますか?問題がまだ述べられているように、実装ではまだ成功していません – Richlewis

+0

@Richlewis更新された答え – Alfie

+1

を参照してください。カウント列を正しい値に初期化するには、 'reset_counters'を使用する必要があることに注意してください。 'http://apidock.com/rails/ ActiveRecord/CounterCache/reset_counters' –

2

counter_cacheに考慮すべき事柄の重要なカップル:特定のRailsのメソッドがコールバックをバイパスして(などのインスタンスupdate_columnupdate_allincrementdecrementdelete_all、のために)データベースを更新し、ことができ

  • カウンターキャッシュの値が矛盾します。 Rails以外のデータベースの変更にも同じことが適用されます。
  • 子モデルを作成/削除するには、常に親を更新する必要があります。カウンタキャッシュの一貫性を保証するために、Railsはこのアップデート中に追加のDBトランザクションを使用します。これは通常問題ではありませんが、子モデルが頻繁に作成または削除されたり、親モデルが頻繁に更新されたりすると、データベースのデッドロックが発生する可能性があります。 (http://building.wanelo.com/2014/06/20/counter-cache-a-story-of-counting.html

これらの問題は、結合テーブル全体でカウンタキャッシュを使用しているため、悪化します。

あなたは、効率的な動的な数をしたい場合は、それは常に最新の状態に、そしてあなたがグループ化されたカスタムselectを使用することができます参加:

@categories = Category.select("categories.*, COUNT(DISTINCT images.id) AS images_count").joins(:images).group("categories.id") 

<% @categories.find_each do |c| %> 
    <li> 
    <%= link_to '#', data: { :filter => '.' + c.name.delete(' ') } do %> 
     <%= c.name %> (<%= c.images_count # <- dynamic count column %>) 
    <% end %> 
    </li> 
<% end %> 

グループ化された本のコストは非常に小さいが提供されるべきで参加しますあなたの外来キーは索引付けされています。私は、images_countが真の値と常に一致する必要がある場合、またはイメージが頻繁に作成または破棄されることが必要な場合は、このアプローチをとることを強く検討します。このアプローチは、長期的に維持することも簡単です。

+0

ありがとう、これは維持するのがずっと簡単に思えますし、レコードを更新するときに私の苦痛を節約します。 – Richlewis

関連する問題