0

モデルにposts_count列を追加しました。Tag

  create_table "tags", :force => true do |t|
    t.string   "name"
    t.datetime "created_at",                 :null => false
    t.datetime "updated_at",                 :null => false
    t.integer  "posts_count", :default => 0, :null => false
  end

今、私はこの質問に基づいてそれらのカウンター キャッシュを構築しようとしています (多対多の関連付けのカウンター キャッシュの作成): 多対多の関連付けを持つモデルのカウンター キャッシュ

post.rb:

private

after_create  :increment_tag_counter_cache
after_destroy :decrement_tag_counter_cache

def increment_tag_counter_cache
  Tag.increment_counter(:posts_count, self.taggings.tag.id)
end

def decrement_tag_counter_cache
  Tag.decrement_counter(:posts_count, self.taggings.tag.id)
end

しかし、次を作成すると、次のようになりますPost

 undefined method `tag' for []:ActiveRecord::Relation

この部分に何か問題があると思いますがself.taggings.tag.id、修正方法がよくわかりません。

助言がありますか?

モデル:

**post.rb:**

     has_many :taggings, dependent: :destroy  
     has_many :tags, through: :taggings

**tag.rb:**

    has_many :taggings, :dependent => :destroy  
    has_many :posts, :through => :taggings

**tagging:**

    attr_accessible :tag_id, :post_id

    belongs_to :post
    belongs_to :tag

編集

post.rb:

  before_save :publish_post

  protected

    def publish_post
      if self.status == "Published" && self.published_at.nil?
       self.published_at = Time.now
      end
    end

tagging.rb:

 private

    def increment_tag_counter_cache
      if self.post.status == "Published" && self.post.published_at.nil?
        Tag.increment_counter(:posts_count, self.tag.id)
      end
    end
4

2 に答える 2

1

この例は少し誤解を招きやすいです...

Taggingモデルにコールバックとカウント コードを配置する必要があります。

private

after_create  :increment_tag_counter_cache
after_destroy :decrement_tag_counter_cache

def increment_tag_counter_cache
  Tag.increment_counter(:posts_count, self.tag.id)  #
end

def decrement_tag_counter_cache
  Tag.decrement_counter(:posts_count, self.tag.id)
end

Post のままにすることもできますが、その場合、割り当てられたすべてのタグのカウンターをインクリメントする必要があります。このコードは、投稿モデルがそのタグを既に認識している場合に実行する必要があります (アプリのロジックによって異なります)。

def increment_tag_counter_cache
  tags.each do |tag|  # if .tags contain Tag objects... or has_many :tags, :through => :tagggings
    Tag.increment_counter(:posts_count, tag.id)
  end
end

しかし、このコードは Post のままにしておきます - 悪い考えです。投稿を更新するときはどうしますか?コードによると、カウンターが再びインクリメントされます。新しいタグを追加したり、削除したりするときに何をしますか。そのようなケースごとに特別なコードを書く必要があります。最悪だ。

于 2012-12-28T12:10:06.853 に答える
1

HOWTO :status = "Published" を持つ投稿のみのカウンターをインクリメントする

投稿モデル:

after_save :increment_tag_counters # covers :save, :create, :update methods
before_destroy :correct_tag_counters

def published?
  self.status == "Published"
end

def increment_tag_counters? # if changes provided and previous status wasn't "published"
  status_changed? && changed_attributes["status"] != "Published"
end

def decrement_tag_counters? # if changes provides and previous status was "published"
  status_changed? && changed_attributes["status"] == "Published"
end

def increment_tag_counters
  if published? && increment_tag_counters?
    taggings.each {|tagging| tagging.increment_tag_counter_cache}
  elsif decrement_tag_counters?
    taggings.each {|tagging| tagging.decrement_tag_counter_cache}
  end
end

def correct_tag_counters
  if published?
    taggings.each {|tagging| tagging.decrement_tag_counter_cache}
  end
end

タグ付けモデル:

after_create  :increment_tag_counter_cache
after_destroy :decrement_tag_counter_cache

def increment_tag_counter_cache
  Tag.increment_counter(:posts_count, self.tag.id) if post.published?
end

def decrement_tag_counter_cache
  Tag.decrement_counter(:posts_count, self.tag.id) if !post.published? || post.decrement_tag_counters? 
end
于 2012-12-28T15:27:58.387 に答える