Railsのhas_manyにおけるsize, count, lengthの違い

掲示板アプリみたいなのを想像する。投稿をPostとしてそれにCommentを複数つけられるシンプルなものだ。Post:Commentが1:Nの関係だ。

環境

p = Post.first

#count

[2] pry(main)> p.comments.count
   (0.3ms)  SELECT COUNT(*) FROM `comments` WHERE `comments`.`post_id` = 1
=> 1
[3] pry(main)> p.comments.count
   (0.5ms)  SELECT COUNT(*) FROM `comments` WHERE `comments`.`post_id` = 1
=> 1

常にSQLでCOUNT文を流してる。

#size

commentsがロードされている場合、そのcommentsのsizeを返す

[14] pry(main)> p.comments
  Comment Load (0.4ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 1
[15] pry(main)> p.comments.size
=> 1

commentsがロードされてない場合、countと同じ

[4] pry(main)> p.comments.size
   (0.3ms)  SELECT COUNT(*) FROM `comments` WHERE `comments`.`post_id` = 1
=> 1
[5] pry(main)> p.comments.size
   (0.3ms)  SELECT COUNT(*) FROM `comments` WHERE `comments`.`post_id` = 1
=> 1

※ 0件の場合は、p.comments.sizeを呼ぶと、その時点でロードされたことになって二度目からはキャッシュされた値を使うので注意。

#length

commentsがロードされている場合、そのcommentsのsizeを返す

[20] pry(main)> p.comments.length
=> 1

commentsがロードされていない場合、commentsをロードしてそのsizeを返す

[18] pry(main)> p.comments.length
  Comment Load (0.3ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 1
=> 1

まとめ

常にCOUNT文による件数が欲しい場合は、#countを使う。それ以外は、#sizeでOK。#lengthはまぁ使うことはあまりなさそうかな。