Как исправить эти методы increment/decment_tag_counter_cache?

Я добавил столбец 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

Now I'm trying to build a counter cache for them based on this question (creating a counter cache for a many-to-many association): Counter cache for a model with a many-to-many association

<�Сильный> 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
0
добавлено отредактировано
Просмотры: 1

2 ответы

Этот пример немного вводит в заблуждение ...

Вы должны поместить обратные вызовы и счетные коды в модель Маркировка :

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 - плохой идее. Что вы будете делать, обновляя сообщение? Согласно коду, он снова увеличит счетчики. Что вы будете делать при добавлении новых тегов или удалении: вам нужно написать специальный код для каждого такого случая. Это отстой.

1
добавлено
Но я думаю, что мне все равно нужно поместить его в post.rb , потому что я хотел увеличить счетчик только для сообщений с : status = "Published" .
добавлено автор alexchenco, источник
если я не сделаю что-то вроде self.post.status условно в taggings.rb ?
добавлено автор alexchenco, источник
Благодаря! Ты действительно спас день сегодня.
добавлено автор alexchenco, источник
добавлен еще один ответ
добавлено автор Valery Kvon, источник

HOWTO increment the counter for only posts that have :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
1
добавлено
Спасибо, что сработало! Хотел бы я проверить оба ваши ответа.
добавлено автор alexchenco, источник
Привет, благодаря работе кода. Единственная проблема заключается в том, что счетчик не уменьшается, когда меняю статус с «Опубликовано» на «Черновик».
добавлено автор alexchenco, источник
Да, извините, я немного запутался, так что ваш код покрыл это?
добавлено автор alexchenco, источник
О, а не код, но ваш комментарий: вы можете обновить сообщение, которое ранее не было опубликовано, а счетчик должен быть увеличен, status может быть Draft и Опубликовано . Счетчик не должен увеличиваться, если пост Черновик . Я думаю, что ваш код не охватывал это?
добавлено автор alexchenco, источник
Не уверен, если я неправильно понял, но я не хочу увеличивать счетчик, если сообщение «Черновик».
добавлено автор alexchenco, источник
Благодаря! Я не совсем понимаю код, но я буду изучать его. Один вопрос: если я использую то, что находится в post.rb , мне также нужно добавить код в tagging.rb вправо?
добавлено автор alexchenco, источник
Я попробую ваш первый фрагмент кода. Я думаю, что он выполняет то же самое, что и мое? (предотвращение увеличения счетчика при редактировании и сохранении сообщения.
добавлено автор alexchenco, источник
Еще раз спасибо, вы мне очень помогли. Я сделал что-то подобное: if self.status == «Опубликован» && self.published_at.nil? (так что счетчик не увеличивается каждый раз, когда сообщение сохраняется). Но по какой-то причине счетчик не делает 't увеличивается из-за части self.published_at.nil? . Я добавил связанный код в свой EDIT (возможно, потому, что добавляю обратный вызов внутри обратного вызова?)
добавлено автор alexchenco, источник
Я обновил код. Методы приращения и уменьшения не должны быть частными ...
добавлено автор Valery Kvon, источник
Быть осторожен. Помните, что вы можете обновлять сообщение, которое ранее не было опубликовано, а счетчик должен быть увеличен, или вы можете сделать его неопубликованным, а счетчик должен быть уменьшен, вы можете просто назначить тег (создать модель тегов), а модель Tagging должна знать все опубликовано сообщение или нет ... Покройте все случаи!
добавлено автор Valery Kvon, источник
да, моя концепция кода сообщения использует код тегов, вы должны его повсюду. О втором вопросе. О какой части кода вы говорите?
добавлено автор Valery Kvon, источник
Это верно. «который не был опубликован раньше». Представьте, что у вас есть пост в черновике. В этом случае счетчики не должны меняться. Затем вы отредактировали сообщение и сделали его общедоступным! Что теперь? Поскольку он публично, он должен менять счетчики тегов. Правильно?
добавлено автор Valery Kvon, источник
Я надеюсь )))
добавлено автор Valery Kvon, источник
обновляется с if! post.published? || post.decrement_tag_counters?
добавлено автор Valery Kvon, источник
проверьте там stackoverflow.com/questions/14078546/… )))
добавлено автор Valery Kvon, источник