Обновление загруженных ассоциаций в памяти - PullRequest
2 голосов
/ 17 апреля 2009

В моем текущем приложении rails я извлекаю много данных из базы данных в память, чтобы я мог запускать длительное фоновое задание, при котором я не хочу запускать базу данных каждые 5 секунд.

Все это прекрасно работает, но у меня есть не очень элегантный код, от которого я хотел бы избавиться, если это возможно.

Например, у меня есть ситуация, когда у меня есть модель пользователя, и эта модель пользователя может связываться с другими моделями пользователей в форме контактов, которые, в свою очередь, могут ссылаться на первую модель пользователя и так далее. Это смоделировано следующим образом (спасибо Милане Новоте за его раннюю помощь): -

class User < ActiveRecord::Base
  has_many :contact_records, :foreign_key => :owner_id
  has_many :contacts, :through => :contact_records, :class_name => "User"
end

class ContactRecord < ActiveRecord::Base
  belongs_to :owner, :class_name => "User"
  belongs_to :user
end

Так что теперь я могу набрать

user_a_contacts = user_a.contact_records
=> [user_b, user_c]

и получить все контакты для пользователя а. Теперь предположим, что я хочу получить контакты пользователя b через пользователя a (не могу понять почему, но это только пример!)

user_b_contacts = user_a_contacts.first.contact_records
=> [user_a, user_c]

Теперь я могу получить имя пользователя a (извилистым, окольным способом, который никогда не будет использоваться в реальном мире)

user_a_name = user_b_contacts.first.name
=> "Jamie"

Пока все хорошо. Теперь я меняю имя пользователя a

user_a.name = "Sandy"
=> "Sandy"

При повторном обращении к имени пользователя a из базы данных, как и раньше, я получаю

user_a_name = user_b_contacts.first.name
=> "Sandy"

Однако, если я с нетерпением загрузил и сохранил это значение в памяти, я получаю

user_a_name = user_b_contacts.first.name
=> "Jamie"

но выполнение следующего дает мне правильный ответ

user_a.name
=> "Sandy"

Совершенно очевидно, что eager-loading создает разные объекты User для исходных пользователей и те, которые eager-загружаются из объектов ContactRecord.

Итак (наконец-то!) Мой вопрос таков: -

На данный момент я обошел это с помощью

@users.each.detect{|user| user == user_b_contacts.first}

(где @users - загруженный список пользовательских объектов). Есть ли способ, которым я могу обновить загруженные пользователем объекты User вместо этого?

Обратите внимание: -

a) Я жду загрузки с использованием следующего

User.find(:all, :include => [ {:contact_records => :contacts] } ])

б) Очевидно, что это не тот код, с которым я работаю, но было бы еще больше объяснений и объяснений, чтобы показать этот код, и я думаю, что вам достаточно скучно! Поверьте мне, что настоящий пример, который я использую, требует, чтобы эта структура работала правильно, как бы странно это ни выглядело! ;)

в) Я мог ввести опечатки и ошибки при реконструкции примера, но, пожалуйста, игнорируйте их. Все, что мне нужно знать, это возможность перезагрузить загруженных пользователей, не обращаясь к базе данных.

Заранее большое спасибо!

ОБНОВЛЕНИЕ: Как упоминалось ниже, данные модели не будут сохранены в базе данных до самого конца выполнения процесса, поэтому перезагрузка не будет работать, так как данные в базе данных не изменились.

Ответы [ 2 ]

4 голосов
/ 17 апреля 2009

OK. Я собираюсь сжать ваш вопрос в новый вопрос и ответить на него. Простите, если я неправильно понял, и это не то, что вы спрашиваете.

Вопрос

Если user - это модель ActiveRecord, где я заранее загрузил ассоциацию contacts с User.first(:include => :contacts), как мне обновить ассоциацию contacts, когда она изменилась в базе данных?

Ответ

Вы можете сделать недействительным кеш ассоциации двумя известными мне способами. Сначала вы можете сделать:

user.reload

, который перезагрузит всю пользовательскую модель с нуля. Немного менее радикальный способ сделать это -

user.clear_association_cache

, который не перезагрузит все user, но очистит кешированные ассоциации.

В любом случае, в следующий раз, когда вы сделаете user.contacts, он снова загрузит их из базы данных.

0 голосов
/ 17 апреля 2009

Большое спасибо за ваш ответ, Даниэль. Пока вы не совсем правильно поняли вопрос, вы заставили меня понять, что я упустил важный момент! Запись базы данных не будет обновлена, так как я не делаю сохранения! в любой момент.

Суть того, что я делаю, это извлечение данных модели в переменные экземпляра для ускорения фонового процесса. Таким образом, данные, которые загружаются в первый раз, не будут сохранены обратно в базу данных до самого конца выполнения процесса.

То, на что я надеялся, было способом, который вы могли бы указать при стремительной загрузке, что значение одного столбца относится к другой загруженной модели.

Например,

User.find(:all, :include => [ {:contact_records => (:contacts as User)] } ])

или аналогичный.

Насколько я знаю, в Rails такого синтаксиса нет, однако я надеюсь, что я ошибаюсь! :)

Надеюсь, это прояснит ситуацию, и еще раз спасибо за ответ.

...