Как получить размер записи own_to - PullRequest
0 голосов
/ 06 июля 2019

Я следовал этому туториалу , чтобы сделать такой же раздел комментариев на моем сайте, и теперь я хочу отобразить количество комментариев к статье, но у меня может быть только количество ответов на статью, не включая количество ответов комментариев.

Я не хочу добавлять столбец к моей модели комментариев со ссылкой на идентификатор статьи, потому что мой сайт уже подключен к сети, и все старые сообщения будут иметь 0 комментариев, потому что у них не будет этого нового столбца.

Есть идеи, как я могу это сделать? Я думаю, это как-то связано с belong_to, но на официальном документе я не могу его найти.

Мой model/comment.rb

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
  has_many :comments, as: :commentable
  serialize :report, Array

  validates :commenter, presence: true, length: { in: 1..500 }
end

мой model/article.rb

class Article < ApplicationRecord
  include BCrypt
  serialize :view, Array
  serialize :upvote, Array
  serialize :report, Array


  has_many :comments, as: :commentable, dependent: :destroy
  validates :title, presence: true, length: { in: 1..60 }
  validates :content, presence: true
  has_secure_password

end

EDIT:

Может быть, я мог бы сделать метод в моем помощнике с циклом, который будет считать каждый комментарий комментария, но я не знаю, как я мог бы сделать этот цикл как Article.find(my_article_id).comments.each do, и тогда я не знаю, как это сделать, тогда, возможно, я должен сделать как Comment.comments.each do?

Я думал сделать рекурсивный метод, но я всегда изо всех сил пытался сделать рекурсивный метод

EDIT2:

schema/article

  create_table "articles", force: :cascade do |t|
    t.string "title"
    t.string "author"
    t.string "author_ip"
    t.string "password_digest"
    t.text "content"
    t.string "upvote"
    t.integer "upvote_count", default: 0
    t.string "view"
    t.integer "view_count", default: 0
    t.string "report"
    t.integer "report_count", default: 0
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.boolean "activate", default: true
    t.integer "comments_count", default: 0, null: false
  end

schema/comment

create_table "comments", force: :cascade do |t|
    t.text "commenter"
    t.string "author"
    t.string "author_ip"
    t.string "date"
    t.integer "commentable_id"
    t.string "commentable_type"
    t.string "report"
    t.integer "report_count", default: 0
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "article_id"
  end

EDIT3:

comment migration

class AddCommentsCountToComments < ActiveRecord::Migration[5.2]
  def change
    add_column :comments, :comments_count, :integer, default: 0,  null: false

    Comment.reset_column_information # to reset cached values
    Comment.find_each do |comment|
      comment.update(comments_count: comment.comments.count) # updating old articles comments_counter
    end
  end
end

Ответы [ 2 ]

0 голосов
/ 06 июля 2019

Вы всегда можете использовать article.comments.size, но это не идеально, так как всегда будет делать запросы к базе данных.

Другим способом является добавление столбца кэша счетчика comments_count в модель articles, также можно обновить comments_count для любой статьи, созданной до кэша счетчика в той же миграции.

Вы можете начать с добавления миграции

  def change
    add_column :articles, :comments_count, :integer, default: 0, null: false

    Article.reset_column_information # to reset cached values
    Article.find_each do |article| 
      article.update(comments_count: article.comments.count) # updating old articles comments_count
    end
  end

Теперь, если вы запустили миграцию и проверили в консоли статьи, сделанные до этой миграции, comments_count должно отражать количество комментариев к статьям.

Теперь последний шаг - добавить опцию counter_cache к вашей модели comment. Параметр counter_cache гарантирует, что число в столбце comments_count всегда обновляется при добавлении или удалении комментария.

belongs_to :commentable, polymorphic: true, counter_cache: true

Теперь, чтобы получить кэшированное значение, вы можете использовать:

  • article.comments.size, как если бы вы использовали counter_cache в ассоциации has_many, size будет напрямую использовать кэшированный счетчик и вообще не будет выполнять никаких запросов.
  • article.comments_count.

Аналогично, чтобы иметь кэшированное значение comment.comments.count или comment.comments_count, вам также необходимо добавить еще один кэш счетчика для таблицы comments.

Чтобы получить все комментарии, включая вложенные комментарии для конкретной article, необходимо получить количество комментариев к статье (внешние комментарии) + количество комментариев к каждому комментарию.

article.comments_count + article.comments.sum(:comments_count)

Чтобы высушить код, если вам нужно его повторно использовать, вы можете добавить метод экземпляра внутри вашей article модели следующим образом:

def comments_count_including_nested
  comments_count + comments.sum(:comments_count)
end

Тогда вы можете позвонить article.comments_count_including_nested

0 голосов
/ 06 июля 2019

Вы можете получить количество комментариев и дочерних комментариев, например:

article.comments.sum { |comment| 1 + comment.comments.count }

Однако при этом будет выполнен один запрос на родительский комментарий к вашей статье, что не идеально.

Другие способы сделать это:

  • добавление article_id ко всем комментариям и заполнение текущих с помощью миграции
  • с использованием счетчика кэша для комментариев
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...