Rails の関連付けが正しく関連付けられていません
概要
この目的は、コメントがユーザーに属する記事に属するようにすることです。
class User < ApplicationRecord
has_one :profile
has_many :articles, -> {order 'published_at DESC, title ASC'}, dependent: :nullify
has_many :replies, through: :articles, source: :comments
end
class Article < ApplicationRecord
validates :title, :body, presence: true
belongs_to :user
has_and_belongs_to_many :categories
has_many :comments
def long_title
"#{title} - #{published_at}"
end
end
class Comment < ApplicationRecord
belongs_to :article
end
コンソールから返される内容は次のとおりです。
irb(main):048> user.replies
=> []
しかし!
irb(main):049> user.replies.all
Comment Load (0.7ms) SELECT "comments".* FROM "comments" INNER JOIN "articles" ON "comments"."article_id" = "articles"."id" WHERE "articles"."user_id" = ? ORDER BY published_at DESC, title ASC [["user_id", 3]]
=>
[#<Comment:0x0000ffff802d1420
id: 1,
article_id: 1,
name: "guest",
email: "[email protected]",
body: "comment text",
created_at: Tue, 03 Oct 2023 22:05:04.136672000 UTC +00:00,
updated_at: Tue, 03 Oct 2023 22:05:04.136672000 UTC +00:00>]
user.replies が空であるのに .all が表示される理由を誰かが説明できますか。
Articles.last.comments だけを返すと (コメントと記事が 1 つだけあります)、コメントは正常に返されます。では、なぜ私がユーザーに要求したときに、記事はそれをユーザーに渡さないのでしょうか?
解決策
これはおそらく、ActiveRecord クエリのキャッシュが原因です。
コンソールでは、最初に user.replies を呼び出し、UI からコメントを追加してから、コンソールから user.replies を呼び出したことがあるでしょう。したがって、コンソールはキャッシュされた値を返しただけです。お気付きのとおり、結果が返される前に SQL ステートメント (つまり、Comment Load …) がありません。
user.replies.all を実行すると、SQL ステートメントが出力されることがわかります。
最初に user.reload を実行してから user.replies を実行すると、user.replies.all を呼び出した場合と同じ結果が得られるはずです。
おそらく、この問題はコンソールでのみ発生するでしょう。コンソールは初期テストには適していますが、リクエストの実際の動作を確認するには、ブラウザーまたは自動テスト、あるいはその両方でテストを実行するのが最善です。