Rails Devise: Как мне (mem) кэшировать запросы базы данных устройства для объекта пользователя? - PullRequest
6 голосов
/ 25 апреля 2011

Каждый раз, когда я захожу на страницу, прошедшую проверку подлинности, я замечаю, что она выдавала оператор SQL:

Пользовательская нагрузка (0,2 мс) SELECT users. * ОТ users ГДЕ (users. id)= 1) LIMIT 1

(кстати, я использую Rails 3 .. поэтому cache_money кажется решением, и, несмотря на большой объем поиска, я не нашел замены).

Я пыталсямного переопределений в пользовательской модели, и кажется, что вызывается только find_by_sql.Который получает строку всего оператора SQL.Кажется, что-то интуитивно понятное, например find_by_id или find, не вызывается.Я «могу» переопределить этот метод и получить идентификатор пользователя и сделать разумную систему кеша из этого - но это довольно уродливо.

Я также попытался переопределить authenticate_user, который я могу перехватить одну попытку SQL, но затем вызывает current_userКажется, пытается снова.

Просто, мои пользовательские объекты меняются редко, и это печальное состояние - продолжать работать с БД для этого вместо решения memcache.(предположим, что я готов взять на себя всю ответственность за аннулирование указанного кэша с помощью: after_save как части, но не всего этого решения)

Ответы [ 3 ]

13 голосов
/ 25 декабря 2012

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

class User < ActiveRecord::Base

  after_save :invalidate_cache
  def self.serialize_from_session(key, salt)
    single_key = key.is_a?(Array) ? key.first : key
    user = Rails.cache.fetch("user:#{single_key}") do
       User.where(:id => single_key).entries.first
    end
    # validate user against stored salt in the session
    return user if user && user.authenticatable_salt == salt
    # fallback to devise default method if user is blank or invalid
    super
  end

  private
    def invalidate_cache
      Rails.cache.delete("user:#{id}")
    end
end
1 голос
/ 10 августа 2012

Я тоже с этим боролся.

Менее запутанный способ сделать это - добавить метод класса в модель User:

def self.serialize_from_session(key, salt)
  single_key = key.is_a?(Array) ? key.first : key
  Rails.cache.fetch("user:#{single_key}") { User.find(single_key) }
end

Обратите внимание, что я добавляю имя модели к идентификатору объекта, который передается для хранения / извлечения объекта из кэша; Вы можете использовать любую схему, соответствующую вашим потребностям.

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

1 голос
/ 26 апреля 2011

ВНИМАНИЕ: Скорее всего, есть лучший / умный способ сделать это.

Я преследовал эту проблему несколько месяцев назад.Я нашел - или, по крайней мере, я думаю, что нашел - где Devise загружает пользовательский объект здесь: https://github.com/plataformatec/devise/blob/master/lib/devise/rails/warden_compat.rb#L31

Я создал патч обезьяны для этого десериализованного метода в /initializers/warden.rb, чтобы сделатьвыборка из кэша вместо получения.Это было грязно и неправильно, но это сработало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...