【问题标题】:Rails: how can I add two counter_cache columns in one migration?Rails:如何在一次迁移中添加两个 counter_cache 列?
【发布时间】:2016-05-20 05:40:35
【问题描述】:

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

我后来发现我不能将 counter_cache 与has_many through: 关系一起使用。所以我写了一些私有方法来添加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

models/forum.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

models/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

models/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

观点/论坛/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>

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 caching counter


    【解决方案1】:

    您可以将多个 counter_cache 列添加到数据库中,就命名它们而言,您似乎走在了正确的轨道上。为了让它们保持更新,您需要修改您的 ForumThread 和 ForumPost 模型,使其看起来有点像这样:

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

    Rails Guides 上提供了有关 counter_cache 的更多信息。还有一个RailsCast about counter_caches

    【讨论】:

    • 是的,我熟悉如何在模型中设置 counter_cache - 我只是对迁移文件感到好奇。不过,谢谢你添加那部分。我实际上遵循了 RailsCast,它在尝试运行迁移时出错。在尝试运行迁移时遇到错误对于新手来说是一个非常头疼的问题。这就是为什么我想确保迁移文件中的代码是正确的。
    【解决方案2】:

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

    #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
    

    好的参考:“Adding a Counter Cache to Existing Records


    因为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
    

    更新

    我认为问题在于你是using counter_cache on a has_many :through association

    #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 with has_many :through


    如果您使用我上面的代码(用于has_many :through),您最好进入Rails console 并更新各种ForumThreads,如下所示:

    $ 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 with has_many :through),似乎确认您可以将 counter_cache 放入连接模型中。

    虽然我们本身并没有这样做,但我看不出它为什么不起作用。

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

    【讨论】:

    • 那么执行“change_table :forums do...”而不只是“add_column :forums, ....”有什么好处?
    • 没什么,只是更简洁更简洁
    • 感谢您的回复。我有一个成功的迁移。 但是在我的视图中:“&lt;%= pluralize forum.forum_threads.size, 'thread' %&gt; | &lt;%= pluralize forum.forum_posts.size, 'post' %&gt;。” forum_threads 编号已正常重置和更新,但 forum_posts 编号为 0,不会重置或更新。我不知道发生了什么。
    • 好的,我已经让计数器工作了。再次感谢您的有用建议。但是,forum_posts_count 不会重置,也不会在视图中显示确切的size。计数器仅显示我在实现 counter_cache 时创建的论坛帖子。我已将所有文件更新为我目前拥有的文件。 (迁移文件 forum_threads.rbforum_post.rb 已从原始问题修改)。会是迁移文件中的内容吗?
    • 好吧,我在上面使用了您的代码(带有委托)并且 counter_cache 没有工作。我在迁移中有重置计数器的代码,但是如果您再次查看更新的问题,我删除了 forum_posts 的 counter_cache 并编写了私有方法来增加和减少论坛的 forum_posts_count。
    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 2014-05-13
    相关资源
    最近更新 更多