2016-04-30 57 views
0

我正在寻找一种方法来显示有多少imagescategory,但通过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

下面是你的模型应该是这样的:

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 

你需要image_count字段添加到您的categories表和category_countimages表中。

一旦完成添加计数器和字段,您需要重置计数器,以便使用正确的计数值为您的数据库中已存在的记录更新字段。

考虑与 counter_cache
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'将count列初始化为其正确值'http://apidock.com/rails/ ActiveRecord/CounterCache/reset_counters' –

2

几个重要的事情:绕过回调(例如update_columnupdate_allincrementdecrementdelete_all等)

  • 某些Rails的方法可以更新数据库,并能导致计数器缓存的值不一致。这同样适用于Rails之外的任何数据库更改。
  • 创建/删除子模型始终需要更新父级。为了确保计数器缓存的一致性Rails在此更新期间使用额外的数据库事务。这通常不是问题,但是如果您的子模型经常被创建/删除,或者父模型经常更新,可能会导致数据库死锁。 (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