8
votes

Rails Devise: Comment I (MEM) Demande de données de la base de données du Cache Devise pour l'objet utilisateur?

Chaque fois que je frappe une page authentifiée, je remarque que l'élaboration d'une instruction SQL:

Charge utilisateur (0.2ms) Sélectionnez Utilisateurs . * Du Utilisateurs où ( utilisateurs . = 1 ) Limite 1

(J'utilise des rails 3 btw .. alors cache_money semble être une solution et malgré beaucoup de recherche que je n'ai trouvé aucun substitut).

J'ai essayé de nombreuses substitutions dans le modèle d'utilisateur et que seule la recherche_by_sql semble appelée. Qui est passé une chaîne de toute la déclaration SQL. Quelque chose d'intuitif comme Find_By_id ou Trouver ne semble pas être appelé. Je 'peut "remplacer cette méthode et glaner l'utilisateur-id et faire un système de cache raisonnable à partir de celui-ci - mais c'est assez moche.

J'ai aussi essayé d'authentifier_utilisateur sur lequel je peux intercepter une tentative SQL, mais ensuite appelle à Current_User semble l'essayer à nouveau.

Simplement, mes objets d'utilisateur changent rarement et c'est un état triste pour continuer à frapper le DB pour cela au lieu d'une solution memcache. (Supposons que je suis prêt à accepter toutes les responsabilités d'invalidation de ladite cache avec: après_save dans le cadre mais pas toute cette solution)


1 commentaires

Devise fait beaucoup de vérification. Vérifiez que vous veulent à faire (généralement). Mais vous avez raison, une quantité de cela devrait être macabotable. Avez-vous tiré de Ruby-Debug pour déterminer où viennent les différentes trouvailles? Je n'ai pas vu de Find_By_SQL dans la source. L'affaire commune est l'utilisateur connecté qui visite des pages protégées par Devise et Devise s'assure que l'utilisateur est vraiment valide. Si vous pouvez caresser ce voyage aller-retour, vous devriez avoir une grande partie du problème résolu. Plus difficile: il y a plusieurs façons de concevoir peut invalider le cache. Par exemple, si un utilisateur réinitialise le mot de passe.


3 Réponses :


1
votes

AVERTISSEMENT: Il y a probablement une meilleure façon de faire cela.

J'ai chassé ce problème dans quelques mois. J'ai trouvé - ou du moins, je pense que j'ai trouvé - où Devise charge l'objet utilisateur ici: https://github.com/plataformatec/devise /blob/master/lib/devise/rails/warden_compat.rb#l31

J'ai créé un patch de singe pour cette méthode désérialisée dans /initializers/warden.rb pour faire une fetch cache au lieu d'obtenir. Il se sentait sale et mal, mais cela a fonctionné.


1 commentaires

Génial adam. Pourrait être sale et mal - mais en effet ça marche.



1
votes

J'ai tellement lu avec cela aussi.

Une manière moins compliquée de cela consiste à ajouter cette méthode de classe à votre modèle utilisateur: xxx note que je prépare le nom du modèle à l'ID d'objet qui est transmis pour stocker / récupérer l'objet dans le cache; Vous pouvez utiliser n'importe quel système correspondant à vos besoins.

La seule chose à craindre, bien sûr, invalide l'utilisateur dans le cache lorsque quelque chose change. Il aurait été agréable de stocker l'utilisateur dans le cache à l'aide de l'ID de session dans le cadre de la clé, mais la session n'est pas disponible dans la classe modèle et n'est pas transmise à cette méthode par congise. < / p>


0 commentaires

13
votes

Le code suivant mettra en cache l'utilisateur par son identifiant et Invalider le cache après chaque modification.

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


0 commentaires