Допустим, у меня есть следующие модели в Rails:
class Post < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :posts
end
Когда я помещаю экземпляр Post в переменную и вызываю user
, запускается следующий запрос sql один раз, после этого результат сохраняется / кэшируется.
post.user
User Load (0.9ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
#<User id: 1 ...>
post.user
#<User id: 1 ...>
etc.
Однако, когда я go наоборот с user.posts
, он всегда выполняет запрос.
user.posts
Post Load (1.0ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 LIMIT 11
user.posts
Post Load (1.0ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 LIMIT 11
etc.
Если я не преобразую его в массив, в этом случае он будет сохранен.
user.posts.to_a
Post Load (1.0ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 LIMIT 11
user.posts
# No query here.
Но user.posts
по-прежнему создает объект ActiveRecord::Associations::CollectionProxy
, для которого я могу вызывать другие методы activerecord. Так что здесь нет никаких минусов.
Почему это так работает? Это похоже на ненужное влияние на sql оптимизацию. Очевидная причина, по которой я могу придумать, заключается в том, что user.posts
корректно обновляется при создании сообщения после установки user
. Но на самом деле это не так уж много, поскольку переменные в основном устанавливаются и сбрасываются при последовательном запуске действий контроллера. Теперь я знаю, что существует система кеширования, которая показывает CACHE Post
sql в журналах сервера, но я не могу действительно полагаться на это, когда я работаю с объектами activerecord между моделями или с более сложными запросами.
Мне не хватает здесь лучшей практики? Или очевидная настройка, которая исправляет именно это?