Rails:如何在一次迁移中添加两个counter_cache列



我在论坛表格中添加了forum_threads_countforum_posts_count列。forum_threads_count工作得很好。forum_posts_count已重置为"0",而不是显示我在添加计数器缓存列之前创建的所有论坛帖子。这些关系是:Forum has_many :forum_threads、论坛线程has_many:forum_posts和Forum has_many :forum_posts, through: :forum_threads

后来我发现我不能在has_many through:关系中使用counter_cache。所以我写了一些私有方法来添加after_create/after_destroy调用来增加/减少计数器。计数器有效,只是它仍然没有考虑在将这些列添加到论坛表之前创建的所有论坛帖子。我觉得我编写迁移的方式有问题。请帮助并提前感谢您。我感谢这个网站上的每个人帮助人们。

"...add_counters_to_forums_table.rb"(迁移文件(

class AddCountersToForumsTableAgain < ActiveRecord::Migration
def self.up
 change_table :forums do |t|
   t.integer :forum_threads_count, :forum_posts_count, default: 0
 end
  Forum.reset_column_information
  Forum.all.pluck(:id).each do |id|
   Forum.reset_counters(id, :forum_posts)
   Forum.reset_counters(id, :forum_threads)
  end
end
 def self.down
  change_table :forums do |t|
   t.remove :forum_threads_count, :forum_posts_count
  end
 end
end

模型/论坛.rb

class Forum < ActiveRecord::Base
 has_many :forum_threads, -> { order ('updated_at DESC') }, dependent: :destroy 
 accepts_nested_attributes_for :forum_threads
 has_many :forum_posts, through: :forum_threads
 accepts_nested_attributes_for :forum_posts
end

模型/forum_thread.rb

class ForumThread < ActiveRecord::Base
 belongs_to :user
 belongs_to :forum, counter_cache: true
 has_many :forum_posts, dependent: :destroy
 accepts_nested_attributes_for :forum_posts
end

型号/forum_post.rb

class ForumPost < ActiveRecord::Base
 belongs_to :forum_thread, touch: true
 belongs_to :forum 
 belongs_to :user
  after_create :increment_forum_posts_count
  after_destroy :decrement_forum_posts_count
private
 def increment_forum_posts_count
  Forum.increment_counter( 'forum_posts_count', self.forum_thread.forum.id )
 end
 def decrement_forum_posts_count
  Forum.decrement_counter( 'forum_posts_count', self.forum_thread.forum.id )
 end
end

views/forums/index.html.erb

<%= render 'shared/page_title', title: "Forums" %>
<div class="col-md-10 col-md-offset-1">
<div class="actions">
 <%= link_to "Create New Forum", new_forum_path, class: 'btn btn-primary' %>
    <div class="pull-right">
        <%= form_tag @forum_thread, method: :get do |f| %>
            <%= text_field_tag :q, nil, class: 'form-control', placeholder: 'Search...' %>
        <% end %>
    </div>
</div>
 # LIST FORUMS WITH THREADS AND POSTS COUNTER CACHE
<div class="list-group">
    <% @forums.each do |forum| %>
            <a href="<%= forum_forum_threads_path(forum.id, @forum_threads) %>" class="list-group-item">                
                <h3><%= forum.title %>
                    <div class="pull-right small">                  
                        <%= pluralize forum.forum_threads.size, 'thread' %> |                           
                        <%= pluralize forum.forum_posts.size, 'post' %>                         
                    </div>
                </h3>               
        </a>            
    <% end %>
</div>

您可以向数据库添加多个counter_cache列,就命名它们而言,您似乎走在正确的轨道上。为了保持它们的更新,您需要修改您的论坛线程和论坛帖子模型,使其看起来像这样:

ForumThread < ActiveRecord::Base
  ...
  belongs_to :forum, counter_cache: true
  ...
end
有关

counter_cache的更多信息,请参阅Rails Guides。还有一个关于counter_caches的RailsCast,

您的迁移看起来不错; 您可以这样改进它:

#db/migrate/add_counters_to_forums_table_....rb
class AddCountersToForumsTable < ActiveRecord::Migration
  def self.up
    change_table :forums do |t|
      t.integer :forum_threads_count, :forum_posts_count, default: 0
    end
    Forum.all.pluck(:id).each do |id|
      Forum.reset_counters(id, :forum_posts_count)
      Forum.reset_counters(id, :forum_threads_count)
    end
  end
  def self.down
    change_table :forums do |t|
      t.remove :forum_threads_count, :forum_posts_count
    end
  end
end

良好参考:"向现有记录添加计数器缓存">


由于counter_cache是在关联上定义的,因此只要将其附加到不同的关联,就可以根据需要拥有任意数量的关联:

#app/models/forum.rb
class Forum < ActiveRecord::Base
  has_many :forum_threads
  has_many :forum_posts
end
#app/models/forum_thread.rb
class ForumThread < ActiveRecord::Base
  belongs_to :forum, counter_cache: true
end
#app/models/forum_post.rb
class ForumPost < ActiveRecord::Base
  belongs_to :forum, counter_cache: true
end

更新

我认为问题是您在has_many :through关联上使用counter_cache

#app/models/forum.rb
class Forum < ActiveRecord::Base
  has_many :forum_threads
  has_many :forum_posts, through: :forum_threads
  delegate :forum_posts_count, to: :forum_threads
end
#app/models/forum_thread.rb
class ForumThread < ActiveRecord::Base
  belongs_to :forum
  has_many :forum_posts
end
#app/models/forum_post.rb
class ForumPost < ActiveRecord::Base
  belongs_to :forum_thread, counter_cache: true
end

这是一个很好的参考:counter_cache has_many :通过


如果您使用了我上面的代码(用于has_many :through(,则最好进入Rails控制台并更新各种ForumThread,如下所示:

$ rails c
$ forums = Forum.all
$ forums.each do |forum|
$  forum.forum_posts.pluck(:id).each do |id|
$    ForumPost.reset_counters(id, :forum_posts_count)
$  end
$ end

应该会为您正确重置计数器。


更新

关于你的问题,我仍然觉得你可以让counter_cache与has_many :through一起工作。我阅读了本教程(counter_cache has_many :through(,似乎确认您可以将counter_cache放在连接模型中。

虽然我们本身没有这样做,但我认为没有理由不这样做。

在你的ForumPost,你真的不需要belongs_to :forum——这应该只适用于ForumTopic

最新更新