#210 Customizing Devise
- Download:
- source codeProject Files in Zip (164 KB)
- mp4Full Size H.264 Video (13.2 MB)
- m4vSmaller H.264 Video (8.32 MB)
- webmFull Size VP8 Video (23.3 MB)
- ogvFull Size Theora Video (17.4 MB)
Nel precedente episodio [guardalo, leggilo] abbiamo mostrato come configurare devise per l’autenticazione degli utenti nelle applicazioni Rails. Questa volta, continuando da dove ci siamo interrotti, vi mostreremo come personalizzare devise.
Lavoreremo con la stessa applicazione usata l’ultima volta, per cui avremo già una base di autenticazione funzionante, con pagine per la registrazione, il login e il logout.
Limitare gli accessi
Il prossimo passo che vogliamo fare è limitare determinate azioni ai soli utenti che si sono autenticati. Solo tali utenti dovrebbero poter creare, modificare o cancellare dei progetti. Per fare ciò, dobbiamo cambiare il ProjectsController
, aggiungendo un before_filter
che chiama un metodo fornito da devise, chiamato authenticate_user!
. Questo metodo si assicura che gli utenti siano autenticati e se non lo sono, li ridirige alla pagina di login. Tutti gli utenti dovrebbero poter vedere le action index
e show
, per cui aggiungiamo un parametro :except
per escludere tali action dal filtro:
class ProjectsController < ApplicationController before_filter :authenticate_user!, :except => [:show, :index] def index #resto della classe
Se clicchiamo sul link “New Project” ora che non siamo autenticati, saremo mandati alla pagina di login:
Questo sistema funziona bene se le vostre autorizzazioni sono semplici e l’unica necessità è quella di garantire che un utente sia autenticato per poter svolgere determinate azioni. Per criteri di autorizzazione più complessi, abbiamo bisogno di una soluzione aggiuntiva tipo CanCan, che è stata trattata nell’episodio 192 [guardalo, leggilo] e che può essere usata con devise.
Personalizzare le viste di Devise
Ora vi faremo vedere come personalizzare il modo in cui si presentano le viste di devise. Se avete intrapreso molti sforzi nella cura dell’aspetto del vostro sito, allora sicuramente vorrete che le form fornite da devise appaiano esattamente come tutte le altre form dell’applicazione. Dal momento che devise è un motore Rails, fornisce le proprie viste, ma queste ultime possono essere facilmente rimpiazzate aggiungendole all’interno della vostra applicazione; devise fornisce un generatore per rendere tutta l’operazione di copia di queste viste semplice. Dalla cartella radice della nostra applicazione, possiamo lanciare rails generate devise_views
e i file della vista saranno creati per noi:
$ rails generate devise_views create app/views/devise create app/views/devise/confirmations/new.html.erb create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erb create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions/new.html.erb create app/views/devise/shared/_links.erb create app/views/devise/unlocks/new.html.erb
Questo comando copia tutte le viste dal motore Rails devise, in modo che ora possiamo modificarle per adattarle alle nostre necessità. Per esempio, di sotto è riportato il codice della vista per la pagina di registrazione che abbiamo visto prima:
/app/views/devise/sessions/new.html.erb
<h2>Sign in</h2> <%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> <p><%= f.label :email %></p> <p><%= f.text_field :email %></p> <p><%= f.label :password %></p> <p><%= f.password_field :password %></p> <% if devise_mapping.rememberable? -%> <p><%= f.check_box :remember_me %> <%= f.label :remember_me %></p> <% end -%> <p><%= f.submit "Sign in" %></p> <% end %> <%= render :partial => "devise/shared/links" %>
Modifichiamo questa vista in questo modo:
<% title "Sign In" %> <%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> <ol class="formList"> <li><%= f.label :email %> <%= f.text_field :email %></li> <li><%= f.label :password %> <%= f.password_field :password %></li> <% if devise_mapping.rememberable? -%> <li><%= f.check_box :remember_me %> <%= f.label :remember_me %></li> <% end %> <li><%= f.submit "Sign in" %></li> </ol> <% end %> <%= render :partial => "devise/shared/links" %>
Nel codice riportato sopra abbiamo sostituito l’intestazione con una chiamata al metodo title
che è fornito dal plugin nifty generators di Ryan Bates. In questo modo il titolo comparirà anche nella finestra del browser. (Questo trucchetto è stato trattato nell’episodio 30 [guardalo, leggilo].) Abbiamo anche cambiato il layout della pagina in modo che gli elementi della form siano renderizzati come elementi di una lista. Con un po’ di stili CSS questo stratagemma può essere utilizzato per posizionare ogni etichetta di ogni campo di testo in modo tale che compaia vicina al proprio campo:
possono essere personalizzate tutte le altre viste in un modo analogo, affinchè si integrino perfettamente col resto della vostra applicazione.
Personalizzare i messaggi di errore
Devise usa una serie di messaggi di errore che vengono mostrati quando qualcosa va storto. Per esempio, se si immette un indirizzo email o una password non corretta, si vedrà il messaggio “Invalid email or password”. Tutti questi messaggi sono memorizzati in un file i18n (locale), rendendo semplici le modifiche per cambiarli o tradurli in altre lingue. Nel file di internazionalizzazione riportato sotto abbiamo cambiato il messaggio devise.failure.invalid
:
en: errors: messages: not_found: "not found" already_confirmed: "was already confirmed" not_locked: "was not locked" devise: failure: unauthenticated: 'You need to sign in or sign up before continuing.' unconfirmed: 'You have to confirm your account before continuing.' locked: 'Your account is locked.' invalid: 'OH NOES! ERROR IN TEH EMAIL!' invalid_token: 'Invalid authentication token.' timeout: 'Your session expired, please sign in again to continue.' inactive: 'Your account was not activated yet.' sessions: signed_in: 'Signed in successfully.' signed_out: 'Signed out successfully.' #rest of file omitted.
Quando proviamo ad autenticarci sbagliando apposta l’indirizzo email, viene mostrato il messaggio di errore aggiornato:
Tutto ciò per quel che riguarda i messaggi di errore, ma che fare riguardo agli errori di validazione mostrati da devise, per esempio quando qualcuno inserisce dettagli non corretti in fase di registrazione?
Nella cartella /config/initializers
dell’applicazione c’è un file chiamato devise.rb
che contiene una svariata serie di opzioni che possiamo usare per configurare devise. Queste opzioni sono ben documentate, per cui è semplice capire quali occorre modificare per fare determinati cambiamenti. Per cui, se volessimo ridurre il numero minimo di caratteri che una password deve avere a quattro caratteri dai sei di default, potremmo semplicemente de-commentare l’ultima riga di questa parte del file e fare l’opportuna modifica. Notere che occorre riavviare il server per apportare le modifiche.
# ==> Configuration for :validatable # Range for password length # config.password_length = 6..20
Se vogliamo andare oltre, possiamo rimuovere l’insieme di default di validazioni e sostituirlo con uno nostro. Se guardiamo nel nostro modello User
, vediamo una lista di moduli devise usati dalla nostra applicazione, uno dei quali è :validatable
:
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :lockable, :timeoutable and :activatable # :confirmable, devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable # Setup accessible (or protected) attributes for your model attr_accessible :email, :password, :password_confirmation end
Il modulo :validatable
gestisce le validazioni dell’email e della password in fase di registrazione. Se vogliamo cambiare quel comportamento, possiamo rimuovere quel modulo e gestire da noi la validazione. I valori di default nel modulo validatable sono validi per la maggior parte degli intenti, per cui per ora li lasceremo come sono.
Routing
Ora vediamo come personalizzare gli instradamenti. Di default, la pagina di registrazione si trova al percorso /users/sign_up
, ma noi vogliamo cambiarlo in /register
. Quando abbiamo lanciato il generatore di devise nell’ultimo episodio, questo ha creato un route chiamato devise_for :users
. Possiamo cambiare questo route con un numero di parametri differenti per modificare gli instradamenti per venire incontro alle nostre necessità:
ProjectManage::Application.routes.draw do |map| devise_for :users resources :projects root :to => 'projects#index' end
Uno dei parametri che possiamo aggiungere è chiamato :path_names
e lo possiamo usare per cambiare l’instradamento verso la pagina di registrazione.
ProjectManage::Application.routes.draw do |map| devise_for :users, :path_names => { :sign_up => "register" } resources :projects root :to => 'projects#index' end
Una volta fatta questa modifica, vedremo un errore di routing visitando /users/sign_up e dovremo piuttosto visitare /users/register
. Ci sono molte altre opzioni che si possono passare al route devise_for: sono tutti elencati nella documentazione.
Personalizzare i requisiti di login
Attualmente la nostra applicazine usa un indirizzo email e una password per autenticare gli utenti, ma se volessimo cambiare questo comportamento, in modo tale da chiedere uno username al posto dell’email, lo potremmo fare in modo molto semplice.
La prima cosa che dobbiamo fare è creare una nuova colonna username
nella tabella relativa al modello User
, in che è fattibile generando una opportuna migrazione:
$ rails generate migration add_username_to_users username:string
Una volta creata, lanciamola:
$ rake db:migrate
Poichè abbiamo un solo utente nel nostra database, possiamo rapidamente autenticarci dalla console Rails e impostare un valore per l’attributo username di quell’utente:
$ rails c Loading development environment (Rails 3.0.0.beta2) ruby-1.8.7-p249 > User.first.update_attribute(:username, "eifion") => true
Ora che abbiamo modificato il database, dobbiamo modificare il file di configurazione di devise, de-commentando la linea col comando config.authentication_keys
e cambiandone il suo valore da :email
a :username
.
config.authentication_keys = [ :username ]
Con questo valore impostato, devise userà il campo username come chiave per l’autenticazione. Dobbiamo anche modificare la form di login, naturalmente, per fare in modo che richieda all’utente autenticando lo username, anzichè l’email:
<% title "Sign In" %> <%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> <ol class="formList"> <li><%= f.label :username %> <%= f.text_field :username %></li> <li><%= f.label :password %> <%= f.password_field :password %></li> <% if devise_mapping.rememberable? -%> <li><%= f.check_box :remember_me %> <%= f.label :remember_me %></li> <% end %> <li><%= f.submit "Sign in" %></li> </ol> <% end %> <%= render :partial => "devise/shared/links" %>
Anche la form di registrazione avrà bisogno di essere modificata e dovremo inoltre aggiungere le validazioni opportune agli attributi di modello User
, ma non lo mostreremo in questo episodio.
Una volta riavviato il server per far sì che prenda le modifiche alla configurazione, potremo visitare la pagina di login e autenticarci con uno username anzichè un’indirizzo email.
E’ tutto per questo episodio sulla personalizzazione di devise. Devise è un’ottima soluzione per l’autenticazione nelle applicazioni Rails, con un buon insieme di opzioni di default che facilitano il setup rapido del meccanismo di base, ma con la flessibilità di poter per essere personalizzato secondo le proprie esigenze pressochè in ogni suo aspetto.