#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)
En el episodio anterior [verlo, leerlo] mostrábamos como configurar devise para la autenticación de usuarios en una aplicación Rails. En esta entrega seguiremos por donde lo dejamos y veremos cómo personalizar Devise.
Continuaremos trabajando con la aplicación del episodio anterior, por lo que ya contamos con páginas para registrarnos e iniciar y cerrar sesión.
Restricción de acceso
El siguiente paso que vamos a dar es restringir ciertas acciones para que sólo puedan ser accedidas
por usuarios que hayan iniciado sesión. Por ejemplo, sólo estos usuarios deberían poder
crear, editar o destruir proyectos. Para esto tendremos que modificar ProjectsController
añadiendo un before_filter
que invoque un método de Devise llamado
authenticate_user!
. Este metodo garantiza que el usuario tiene sesión iniciada y si no es
así lo redirige a la página de entrada. Las acciones index
y show
sí que deberían poder ser accesibles para todos los usuarios así que usaremos el
parámetro :except
para que el filtro no afecte a estas acciones.
class ProjectsController < ApplicationController before_filter :authenticate_user!, :except => [:show, :index] def index #rest of class
Si hacemos clic en el enlace “New Project” sin haber iniciado sesión seremos llevados a la página de entrada.
Esta técnica funciona bien para casos de autorización simple (sólo tenemos que asegurarnos de que el usuario ha iniciado sesión). Si necesitamos montar un esquema de autorización más sofisticado tendremos que recurrir a una solución como CanCan, que vimos en el episodio 192 [verlo, leerlo] y que puede combinarse con Devise.
Personalización de las vistas en Devise
A continuación veremos como modificar el aspecto de las vistas en Devise, dado que querremos que las
vistas proporcionadas por Devise se adapten al aspecto general de nuestras páginas. Al ser un Engine de
Rails, Devise proporciona sus propias vistas que pueden adaptarse copiándolas a nuestra propia
aplicación. De hecho Devise proporciona un generador para que sea fácil hacer esto. Desde el
directorio de nuestra aplicación sólo tenemos que ejecutar rails generate
devise_views
y se crearán los ficheros de las vistas.
$ 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
Este comando copia todas las vistas a partir del directorio del Engine por lo que ahora podremos editarlas según nuestras necesidades. A continuación se muestra el código de la vista para la página de registro que vimos anteriormente.
<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" %>
Y lo cambiaremos por:
<% 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" %>
En el código anterior hemos cambiado la cabecera incluyendo una llamada al método
title
que nos facilita el plugin nifty
generators de Ryan Bates. Esto significa que este texto también aparecerá en el
título de la página. (Ya vimos este truco en el episodio 30 [verlo, leerlo].) También hemos cambiado la
maquetación de la página para que los elementos de formulario se muestren como parte de una
lista. Con algunos ajustes de estilo en la CSS podemos hacer que la etiqueta de cada campo aparezca al lado
del campo propiamente dicho.
El resto de las vistas se puede modificar de forma similar para que su aspecto se ajuste al del resto de nuestra aplicación.
Personalización de los mensajes de error
En Devise existen ciertos mensajes de error que aparecen cuando algo va mal. Por ejemplo si se introduce
una clave o dirección de correo incorrecta veremos el mensaje “Invalid email or password”.
Todos estos mensajes están almacenados en un archivo de internacionalización lo que hace que sa
sencillo cambiarlos o traducirlos al idioma que queramos. Nosotros hemos cambiado el mensaje
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.
Si ahora introducimos una dirección de correo electrónico incorrecta se muestra el mensaje modificado.
Con esto cubriríamos los mensajes de error, ¿pero qué pasa con las validaciones de Devise, por ejemplo cuando alguien introduce datos incorrectos cuando se da de alta?
En el directorio /config/initializers
de la aplicación hay un fichero llamado
devise.rb
y este fichero contiene muchas opciones de configuración de Devise. Están
bien documentadas por lo que es fácil averiguar cuáles son las que tenemos que modificar si
queremos hacer cambios. Así, si queremos reducir el tamaño mínimo de caracteres de la
clave de cuatro a seis caracteres sólo tenemos que descomentar la última línea del
archivo y hacer el cambio necesario. Nótese que tendremos que reiniciar el servidor después de
hacer nuestros cambios.
# ==> Configuration for :validatable # Range for password length # config.password_length = 6..20
Podemos ir un paso más lejos cambiando las validaciones por defecto por las nuestras. Si miramos en
nuestro model User
veremos una lista de los módulo de Devise que estamos utilizando en
nuestra aplicación, y uno de ellos es :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
El módulo :validatable
controla la validación del correo y la clave cuando nos
damos de alta. Si queremos cambiar dicho comportamiento podemos eliminar el módulo y gestionar las
validaciones por nuestra cuenta. Nosotros no lo cambiaremos porque los valores por defecto del módulo
:validatable
son razonablemente buenos en la mayoría de los casos.
Rutas
A continuación personalizaremos las rutas. Por defecto la página de registro se encuentra en
/users/sign_up
pero queremos que sea /register
. En el episodio anterior, Cuando
ejecutamos el generador de Devise creó una ruta llamada devise_for :users
. Esta ruta
acepta algunos parámetros con los que podemos modificarla.
ProjectManage::Application.routes.draw do |map| devise_for :users resources :projects root :to => 'projects#index' end
Uno de estos parámetros es :path_names
con el que podemos cambiar la ruta de nuestra
página de registro.
ProjectManage::Application.routes.draw do |map| devise_for :users, :path_names => { :sign_up => "register" } resources :projects root :to => 'projects#index' end
Tras hacer este cambio veremos un error de rutas cuando visitemos /users/sign_up
, ahora
tendremos que visitar /users/register
. En la documentación de Devise aparecen todas las
opciones que acepta el método devise_for
.
Ajustes en los requisitos de inicio de sesión
Nuestra aplicación utiliza una combinación de correo electrónica y clave para que los usuarios inicien la sesión pero los cambios para que pregunte un nombre de usuario en lugar del correo son fáciles:
Lo primero que tenemos que hacer es crear una columna username
en la tabla User
,
de lo que por supuesto se encargará una migración.
$ rails generate migration add_username_to_users username:string
Con esto podemos ejecutar la migración,
$ rake db:migrate
Dado que sólo tenemos un usuario en la base de datos podemos entrar en la consola de Rails y
configurar un valor para el atributo username
de este usuario.
$ rails c Loading development environment (Rails 3.0.0.beta2) ruby-1.8.7-p249 > User.first.update_attribute(:username, "eifion") => true
Ahora tenemos que modificar el archivo de configuración de Devise, descomentando la línea que
comienza por config.authentication_keys
y cambiando el valor de :email
a
:username
.
config.authentication_keys = [:username ]
Con esto Devise utilizará como clave de autenticación el campo username
.
También tendremos que hacer cambios en el formulario de inicio de sesión para que solicite el
nombre de usuario en lugar del correo electrónico.
<% 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" %>
También habrá que modificar el formulario de registro y añadir una validación
al modelo User
pero eso queda como ejercicio para el lector.
Tras reiniciar el servidor (para que surtan efecto los cambios de la configuración) podemos visitar la página de inicio de sesión y entrar con un nombre de usuario en lugar de la dirección de correo.
Esto es todo por este episodio en el que hemos visto cómo hacer cambios en la configuración de Devise.