#13 Dangers of Model in Session
Dans cet épisode, nous allons vous montrer pourquoi c'est une mauvaise idée de stocker un modèle dans une session.
class UserController < ApplicationController def prepare session[:user] = User.find(:first) redirect_to :action => :'show' end def show @user = session[:user] end def update @user = session[:user] @user.name = 'Foo' redirect_to :action => 'show' end end
Contrôleur avec des actions qui stockent un modèle en session.
Dans le code précédent, nous avons un contrôleur avec trois actions. La première action, prepare, cherche le premier User, le stocke dans la session, puis redirige vers l'action show. L'action show prend le premier utilisateur à partir de la session et affiche certaines informations de debug concernant l'utilisateur.
<%= debug(@user) %> <%= link_to 'update', :action => 'update' %>
Le code de la vue show.
La vue show a un lien vers l'action update. L'action update récupère l'utilisateur courant depuis la session à nouveau, modifie une de ses propriétés puis redirige vers show. La modificaition effectuée dans update devrait être temporaire puisqu'elle n'est pas répercutée en base de données. Finallement, update redirige vers show donc nous pouvons voir les propriétés de l'utilisateur à nouveau.
Nous allons d'abord à /user/prepare qui va commencer par mettre l'utilisateur en session puis rediriger vers show. Dans show, on peut voir que le nom est correct. Ensuite, nous cliquons sur ‘Update’, la propriété name est modifiée et nous redirigeons vers show à nouveau. Le nom est maintenant ‘Foo’, ce qui est différent du nom de l'utilisateur stocké en base de données. Parce que nous avons stocké l'utilisateur en session, n'importe quel changement effectué est persistent au long de la navigation donc chaque fois que l'on récupère l'utilisateur depuis la session, nous verrons l'User modifié plutôt que celui stocké en base de données. Ce qui peut nous amener à quelques bugs délicats.
NooNoo:ep13 eifion$ script/console Loading development environment (Rails 2.2.2) >> User.first.name => "Eifion" >>
L'User dans la base de données à toujours le nom ‘Eifion’.
Problèmes avec les validations
Notre modèle User a une validation qui contrôle que le nom existe (avec validates_presence_of). Nous allons mettre à jour l'action update pour initialiser le nom avec une chaine vide, contrôler que l'utilisateur est valide et voir ce qui se passe.
def update @user = session[:user] @user.name = '' @user.valid? redirect_to :action => 'show' end
L'action update mise à jour.
Maintenant nous avons initialisé le nom avec une chaine vide mais il y a toujours des erreurs. Une fois que nous avons redirigé vers une autre page, les erreurs ne devraient pas persister mais parce que nous avons stocké le modèle en session, elles le font même après redirection. Ceci peut amener à confusion un utilisateur qui pourrait voir des erreurs de validation sur une page et les retrouver quand il reviendra sur la page plus tard.
La bonne façon de faire
Maintenant, nous allons faire ça proprement. Au lieu de stocker le modèle User en session, nous allons stocker l'id de l'utilisateur. Le contrôleur mis à jour ressemblera à ça :
class UserController < ApplicationController def prepare session[:user_id] = User.find(:first).id redirect_to :action => :'show' end def show @user = User.find(session[:user_id]) end def update @user = User.find(session[:user_id]) @user.name = 'Foo' redirect_to :action => 'show' end end
Contrôleur avec actions qui enregistre un id en session.
Maintenant, uniquement l'id est stocké en session et l'utilisateur est récupéré depuis la base de données à chaque requête. Cette fois, le changement fait au nom de l'utilisateur ne persiste pas et reste le même à chaque requête.
Heureusement, cet épisode a montré les dangers du stockage de modèle et autres objets complexes dans une session Rails. L'objet de session devrait seulement être utilisé pour stocker des objets simples comme des tableaux, des chaines ou des entiers.


