我正在寻找一种方法来显示images
的{{1}}数量,但通过category
关联获得。我一直在has_many
上读一点,但对实现还没有任何乐趣
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
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
答案 0 :(得分: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_count
表格中添加images
字段。
完成添加计数器和字段后,您需要重置计数器,以便使用数据库中已存在的记录的正确计数值更新字段。
Category.find_each { |category| Category.reset_counters(category.id, :images) }
Image.find_each { |image| Image.reset_counters(image.id, :categories) }
答案 1 :(得分:2)
counter_cache
要考虑的几件重要事项:
update_column
,update_all
,increment
,decrement
,delete_all
等)和可能导致计数器缓存的值不一致。这同样适用于Rails之外的任何数据库更改。由于您在连接表中使用计数器缓存,因此会加剧这些问题。
如果您想进行有效的动态计数,那么它始终是最新的,那么您可以使用带有分组联接的自定义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
始终与真值保持一致,或者图像是经常被创造或破坏。从长远来看,这种方法也可能更容易维护。