has_manyで複数のレコードが紐づいている状態で、has_oneに変えるとどのレコードが紐づくのかふと気になったので試してみた。
言い換えると、has_many
関係でarticle.comments
が複数取れる状況だった時に、has_one
に変更してarticle.comment
を実行すると、どのレコードを取ってくるのかを見てみた。
結論
created_at, updated_atの値に関係なく、idの一番若いレコードと紐づく
一番新しいレコードを取ってくるのかなぁと思ったらそうではなかった。
上の結論に至るまでの検証を下にまとめていく。
前提
ArticleモデルとCommentモデルを用意し、Article has_many
Commentsの関係をとるとする。
class Article < ApplicationRecord
has_many :comments
# has_one :comment #検証用
end
class Comment < ApplicationRecord
belongs_to :article
end
用意したレコードはarticle1個、comment3個。commentは全てarticleに紐づいてるものとする。
#<Article:0x00007f979bad9f00
id: 1,
title: "title1",
created_at: Tue, 03 Dec 2019 04:54:13 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:54:13 UTC +00:00>
[#<Comment:0x00007f9798e79f28
id: 1,
content: "comment1",
article_id: 1,
created_at: Tue, 03 Dec 2019 04:55:15 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:55:15 UTC +00:00>,
#<Comment:0x00007f9798e79d98
id: 2,
content: "comment2",
article_id: 1,
created_at: Tue, 03 Dec 2019 04:55:23 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:55:23 UTC +00:00>,
#<Comment:0x00007f9798e79c08
id: 3,
content: "comment3",
article_id: 1,
created_at: Tue, 03 Dec 2019 04:55:26 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:55:26 UTC +00:00>]
検証1 上記条件でhas_many => has_oneに変更
上記の状態で article.rb の has_many
をコメントアウトし、 has_one
に変更
Article.first.comment
実行
[1] pry(main)> Article.first.comment
結果
id = 1のcomment
=> #<Comment:0x00007f979b488638
id: 1,
content: "comment1",
article_id: 1,
created_at: Tue, 03 Dec 2019 04:55:15 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:55:15 UTC +00:00>
=> 一番若いidを取ってくる
結論の通り。だけどこれだけではupdated_atとcreated_atの影響の可能性も捨てきれないので、もうちょい掘り下げる。
##検証2 update_atの値を変える
id=1のcommentをアップデートし、updated_at
を他二つより最近のものにする
has_one
に変更し、Article.first.comment
実行
[1] pry(main)> Comment.first.update_attributes(content: "comment1A")
[2] pry(main)> Article.first.comment
結果
id = 1のcomment
=> #<Comment:0x00007f979b675568
id: 1,
content: "comment1A",
article_id: 1,
created_at: Tue, 03 Dec 2019 04:55:15 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:59:09 UTC +00:00>
=> updated_atの値に関係なく一番若いidを取ってくる
updated_atの値を見てわかる通り。
検証3 id=1 のCommentレコードを削除
id=1のcommentを削除
has_one
に変更し、同様に実行
[1] pry(main)> Comment.first.delete
[2] pry(main)> Article.first.comment
結果
id = 2のcomment
=> #<Comment:0x00007f979bbe3540
id: 2,
content: "comment2",
article_id: 1,
created_at: Tue, 03 Dec 2019 04:55:23 UTC +00:00,
updated_at: Tue, 03 Dec 2019 04:55:23 UTC +00:00>
=> 存在しているレコードの中で一番若いidを取ってくる
commentのidが2と3しかない状態なのでこのようになる
検証4 再び id=1 のCommentレコードを追加
検証3を終えた状態 (id=1のcommentを消した状態) で
id=1のcommentを再びcreate。articleに紐づける
has_one
に変更し、同様に実行
[1] pry(main)> Comment.create(id:1, content:"comment1", article_id:1)
[2] pry(main)> Article.first.comment
結果
id = 1のcomment
=> #<Comment:0x00007f979b88a678
id: 1,
content: "comment1",
article_id: 1,
created_at: Tue, 03 Dec 2019 05:05:59 UTC +00:00,
updated_at: Tue, 03 Dec 2019 05:05:59 UTC +00:00>
=> created_atの値に関係なく一番若いidを取ってくる
今までは**"idが一番若い = created_atの値が一番古い"**が成り立ってたたため、これでcreated_atの値が関係ないことがわかった。
一度消したのでid=2をとってくるかと思いきやid=1だった。
終わりに
結論の通り、has_manyからhas_oneに変更した場合、idの一番若いものを取ってくることがわかった。直感的には一番新しいレコードを取ってきそうな気はするけど、そうではないっぽいので気をつけたい。検証不足、間違い等ありましたらコメントお願いしますm(_ _)m