Rails: Почему отношения has_many не сохраняются в переменной / атрибуте, как Own_to? - PullRequest
0 голосов
/ 26 марта 2020

Допустим, у меня есть следующие модели в 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 между моделями или с более сложными запросами.

Мне не хватает здесь лучшей практики? Или очевидная настройка, которая исправляет именно это?

1 Ответ

0 голосов
/ 26 марта 2020

Вы изучаете это в irb, и поэтому вы видите, что запрос всегда выполняется.

В реальном блоке кода в контроллере или другом классе, если вы пишете

@users_posts = user.posts

Запрос НЕ выполняется ... пока вы не выполните итерацию по коллекции или запрос #count

irb, чтобы быть полезным, всегда выполняет запросы немедленно

...