2016-02-13 21 views
0

我已將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_threadsRails 4:使用counter_cache時,計數器顯示「0」而不是實際「大小」

我後來發現我無法使用與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 

型號/ 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 

型號/ 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 

的意見/論壇/ 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> 

回答

0

可以提供進一步的信息,爲什麼你不能使用計數器緩存關於:through的關係?看reset_counter方法,它看起來像有處理這種情況下,代碼:

# File activerecord/lib/active_record/counter_cache.rb, line 20 
def reset_counters(id, *counters) 
    object = find(id) 
    counters.each do |counter_association| 
    has_many_association = _reflect_on_association(counter_association) 
    unless has_many_association 
     has_many = reflect_on_all_associations(:has_many) 
     has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym } 
     counter_association = has_many_association.plural_name if has_many_association 
    end 
    raise ArgumentError, "'#{self.name}' has no association called '#{counter_association}'" unless has_many_association 

    if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection 
     has_many_association = has_many_association.through_reflection 
    end 

    foreign_key = has_many_association.foreign_key.to_s 
    child_class = has_many_association.klass 
    reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? } 
    counter_name = reflection.counter_cache_column 

    stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({ 
     arel_table[counter_name] => object.send(counter_association).count(:all) 
    }, primary_key) 
    connection.update stmt 
    end 
    return true 
end 

這麼一件事我會嘗試在更新到最新的穩定版本的軌道,運行在該列reset_counter並再次檢查。

歷史顯示,rails對計數器有很多細微的問題,建議您隨時調整計數,因爲它們不同步(即人們從db中手動刪除記錄)。

+0

我還是比較新的鐵軌。我正在使用Rails 4.2.1。我將如何去下載最新的穩定版本?另外,我遵循[本教程](http://www.eyupatis.com/rails-has-many-through-association-with-counter-cache-argument/),forum_posts_count返回了forum_threads的數量而不是forum_posts。 @phoet – BB123

0

必須編寫另一個遷移來處理計數器本身。

class CacheForumForumPostsCount < ActiveRecord::Migration 

def up 
    Forum.find_each do |forum| 
    forum_threads = ForumThread.where(forum_id: forum.id) 
    post_counter = 0 
    forum_threads.each do |ft| 
     post_counter += ft.forum_posts.size 
    end 
    forum.update_attributes(forum_posts_count: post_counter) 
end 
end 

def down 

end 
end 
相關問題