Rails 3.0.3 Rails.cache.read не может записывать в БД - PullRequest
2 голосов
/ 12 апреля 2011

Я играю с функцией Rails 3 Rails.cache, и когда я записываю запись ActiveRecord в кеш, я не могу прочитать ее обратно, изменить атрибуты, а затем записать в базу данных. Я получаю «TypeError: не могу изменить замороженный хэш». Раньше я использовал другой плагин memcache, но я пытаюсь переключиться на Heroku, и это невероятно раздражает, что я не могу сохранить записи ActiveRecord, которые я добавляю в Memcache. Это приведет к большому количеству ненужных чтений БД для изменения небольших битов информации.

Например, я мог бы сделать это в базе данных. Предполагая, что пользовательская модель:

Пользователь -> логин: строка и ввод следующего в rails c

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user)
user2 = Rails.cache.read('user:login:test')
user2.login = 'test2'
TypeError: can't modify frozen hash
/app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:26:in `[]='
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:26:in `write_attribute'
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/dirty.rb:61:in `write_attribute'
    /app/.bundle/gems/ruby/1.8/gems/activerecord-3.0.3/lib/active_record/attribute_methods/write.rb:13:in `login='

Кто-нибудь знает, как решить эту проблему?

Ответы [ 2 ]

1 голос
/ 18 октября 2011

После получения значения объекта user2 из этой строки:

user2 = Rails.cache.read('user:login:test')

сделать следующее:

dup_user = user2.dup # this will make a clone of the user2 object
dup_user.login = test_2

Тогда исключение «замороженный хэш» не должно появляться снова.

0 голосов
/ 18 октября 2011

Когда вы сохраняете объект в кеше, объект замораживается. Это одна из причин, по которой вам никогда не следует хранить сложные объекты, такие как модели ActiveRecord.

Когда вы читаете из кэша, объект загружается, но он все еще заморожен. ActiveRecord пытается восстановить состояние объекта, но ему необходимо обновить некоторые внутренние атрибуты. Обновление не будет выполнено, потому что объект заморожен.

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

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user.id)
user2 = User.find(Rails.cache.read('user:login:test'))
user2.login = 'test2'

Это немного менее эффективно с точки зрения кэширования, но это путь. Фактически, вы не учитываете, что в это время другие атрибуты пользователя могли быть изменены, и ваш объект больше не представляет текущий статус.

Кроме того, таким образом, ваше хранилище кэша не будет действовать как база данных, и вы сможете хранить больше записей кэша. Идентификаторы занимают меньше памяти, чем весь экземпляр ActiveRecord.

Конечно, вы можете использовать обходной путь #dup, но это всего лишь уловка. Это не решение. У вас все еще будут проблемы с целостностью кэша, как я объяснил выше.

user = User.new
user.login = 'test'
user.save
Rails.cache.write('user:login:test', user)
user2 = Rails.cache.read('user:login:test').dup
user2.login = 'test2'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...