#13 Dangers of Model in Session
In questo episodio vi mostrerò il perchè è una cattiva idea salvare un modello in sessione.
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
Controller con action che salvano un modello nella sessione.
Nel codice sopra abbiamo un controller con tre action. La prima, prepare
, recupera il primo User
, lo salva nella sessione e infine esegue un redirect alla vista show
. La vista show
prende l’utente corrente dalla sessione e stampa alcune informazioni su tale utente.
<%= debug(@user) %> <%= link_to 'update', :action => 'update' %>
Il codice della vista show
.
La vista show
ha un collegamento alla action update
. L’ action update
prende nuovamente l’utente corrente dalla sessione, cambia una delle sue proprietà e poi ridirige indietro alla vista show
. Le modifiche fatte nella action update dovrebbero essere temporanee dal momento che non sono rese persistenti sul database. Infine, update
ridirige indietro alla vista show
, in modo tale che possiamo rivedere nuovamente le proprietà dell’utente.
Per prima cosa, puntiamo a /user/prepare
che inserisce il primo utente nell’oggetto sessione e ridirige verso la vista show
. Nella show
possiamo vedere che il nome è corretto. Poi clicchiamo ‘Update’, la property name per l’utente è cambiata e siamo ridiretti nuovamente alla vista show
. Il nome ora è ‘Foo’, diverso rispetto al nome di quell’utente così come risulta sul database. Dal momento che abbiamo salvato il modello utente nella sessione, qualsiasi modifica fatta su quel modello è mantenuta fra le varie richieste, per cui ogni volta che otteniamo l’utente dalla sessione, vediamo lo User
modificato piuttosto che quello salvato sul database. Ciò può condurre ad anomalie piuttosto rognose.
NooNoo:ep13 eifion$ script/console Loading development environment (Rails 2.2.2) >> User.first.name => "Eifion" >>
Lo User
sul database ha ancora il nome ‘Eifion’.
Problemi con le validazioni
Il nostro modello User
ha una validazione che controlla che il nome esista (con la validates_presence_of
). Aggiorniamo la action update
in modo tale che imposti il nome ad una stringa vuota e controlli che l’utente sia valido e vediamo che succede.
def update @user = session[:user] @user.name = '' @user.valid? redirect_to :action => 'show' end
La action update
aggiornata.
Ora abbiamo impostato il nome ad una stringa vuota, ma ci sono ancora errori. Una volta che veniamo ridiretti ad un’altra pagina gli errori non dovrebbero rimanere, ma, poichè ci stiamo portando dietro il modello in sessione, continuano ad esserci, anche dopo una ridirezione. Ciò può causare confusione agli utenti che potrebbero vedersi degli errori di validazione in una pagina, per poi ritrovarseli ancora ritornando nella pagina più tardi.
Il modo corretto
Ora faremo la modifica corretta. Anzichè salvare il modello User
nella sessione, ne salviamo solo la chiave primaria (id
). Il codice del controller, aggiornato, sarà il seguente:
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
Controller con le action che salvano un id
nella sessione.
Ora, soltanto l’id
viene salvato in sessione e l’utente ’ recuperato ogni volta dal database per ogni richiesta. Questa volta, la modifica fatta la nome dell’utente non è mantenuta fra le varie richieste.
Speriamo che questo episodio abbia evidenziato i pericoli derivanti dal salvataggio di modelli e altri oggetti complessi nella sessione Rails. L’oggetto di sessione, in definitiva, dovrebbe essere utilizzato solamente per mantenere oggetti semplici come array, stringhe e interi.