본문 바로가기

소프트웨어 이야기/장고와 루비온레일즈

[RAILS] association_basics counter_cache

레일즈 가이드에 counter_cache라는 개념이 있길래, 뭔지 궁금해서 찾아봤다.

class Comment < ApplicationRecord
  belongs_to :post, counter_cache: true
end
class Post < ApplicationRecord
  has_many :comments
end

예를 들어, 

게시물의 리스트를 조회하는 페이지를 만든다고 생각해보자. 이 때, 게시물(Post)에는 댓글(Comment)가 남는 다.

이 때, 아래의 예제 코드처럼, 루프를 돌때마다 댓글의 크기를 세면

N+1 쿼리 문제가 발생하게 된다.

<% @posts.each do |post| %>
  <tr>
    <td><%= post.title %></td>
    <td><%= pluralize(post.comments.size, 'comment') %></td>
  </tr>
<% end %>
Started GET "/posts" for ::1 at 2016-03-16 23:47:08 -0700
  ActiveRecord::SchemaMigration Load (0.2ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by PostsController#index as HTML
  Project Load (0.1ms)  SELECT "posts".* FROM "posts"
(0.2ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 1]]
(0.1ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 2]]
(0.1ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 3]]
Rendered projects/index.html.erb within layouts/application (25.4ms) Completed 200 OK in 202ms (Views: 190.5ms | ActiveRecord: 1.3ms)


이런식으로 사용되는 데이터인 경우, 

아예  Post 테이블에, 전체 댓글 갯수를 저장하는 컬럼을 추가하고,

댓글이 생성될 때마다 게시물의 댓글 갯수를 +1 해주도록 하는 기능이 counter_cache이다.


class AddPostCount < ActiveRecord::Migration[5.0]
  def change
    add_column :posts, :comments_count, :integer, default: 0
  end
end

이렇게 마이그레이트 파일을 만들어서, 기존 테이블에 컬럼을 추가해준다.

그리고 맨 위에 적어둔 것 처럼, association에 counter_cache: true을 추가해주면

comment가 생성될 때 자동으로 post의  comment_count  갯수가 증가한다.

실제로 테스트는 안해봤다. 그런데 블로그 포스팅 내용을 참고해보니, 이렇게 사용하면 된다고 써있었다.


참고 링크 

Counter-Cache-Column-in-Rails-5

association_basics.html#options-for-belongs-to-counter-cache

three-easy-steps-to-using-counter-caches-in-rails/