homeASCIIcasts

160: Authlogic 

(view original Railscast)

Other translations: En

Other formats:

Written by Juan Lupión

template

Uno de los plugins de Rails más populares es Restful Authentication, que repasamos con detalle en el episodio 67. Restful Authentication es un generador que crea bastante código para gestionar la autenticación en nuestras aplicaciones Rails y funciona muy bien como solución rápida de autenticación pero hoy existen alternativas más flexibles y extensibles.

Una de estas alternativas es Authlogic, que utiliza un enfoque diferente al de Restful Authentication en el sentido de que no genera controladores o vistas sino que sólo trabaja con el código que gestiona la autenticación de los usuarios. Debido a esto lleva un poco más de tiempo hacer que nuestra aplicación funcione con Authlogic porque tendremos que escribir más código, pero ganaremos flexibilidad y control acerca de cómo se presenta la autenticación al usuario.

Cómo añadir Authlogic a una aplicación

Arriba podemos ver una página de la aplicación a la que le vamos a añadir autenticación. En la esquina superior derecha de la página queremos añadir un enlace titulado “Registro” y “Entrar” si el usuario no está logado y “Editar perfil” y “Salir” si lo esta.

Instalación de Authlogic

Podemos instalar Authlogic bien como plugin o como gema; nosotros instalaremos la gema. Para añadirlo a nuestra aplicación sólo tenemos que añadir la siguiente línea al archivo /config/environment.rb.

  config.gem "authlogic"
  

Después ejecutaremos rake para asegurarnos de que se ha instalado correctamente la gema.

  sudo rake gems:install
  

Creación del Modelo y del Controlador

Una vez que tenemos Authlogic instalado, lo siguiente que hay que hacer es crear un modelo y un controlador para gestionar a nuestros usuarios. En primer lugar generaremmos nuestro modelo User.

  script/generate model user
  

En siguiente lugar editaremos el fichero de migración generado para configurar las propiedades de nuestro modelo. Authlogic funciona buscando columnas con un determinado nombre en la base de datos. Nuestro fichero de migracion tendrá el siguiente aspecto:

  class CreateUsers < ActiveRecord::Migration
    def self.up
      create_table :users do |t|
        t.string :username
        t.string :email
        t.string :crypted_password
        t.string :password_salt
        t.string :persistence_token
        t.timestamps
      end
    end

    def self.down
      drop_table :users
    end
  end
  

Authlogic reconoce y sabe qué hacer con los campos email, crypted_password, password_salt y persistence_token. Se puede encontrar más información sobre las columnas especiales de Authlogic en la página de Github de la aplicación de ejemplo de Authlogic .

Por último, crearemos la tabla en la base de datos con rake.

  rake db:migrate
  

El modelo User que acabamos de generar es solamente una clase de modelo estandar. Sólo tenemos que añadir la linea acts_as_authentic para añadir la funcionalidad de Authlogic.

  class User < ActiveRecord::Base
    acts_as_authentic
  end
  

acts_as_authentic puede recibir un bloque para especificar otras opciones de configuración pero en nuesro caso los valores por defecto son razonables y no lo haremos en esta ocasión.

Antes de continuar crearemos también nuestro controlador de usuarios. Tendremos que tener vistas new y edit así que se lo diremos al generador.

  script/generate controller users new edit
  

Tendremos que hacer un pequeño ajuste en el fichero de rutas (/config/routes.rb) porque vamos a utilizar este controlador como un recurso REST.

Por ahora podremos dejar el controlador tal y como está. Volveremos en breve para rellenar los métodos y vistas que faltan.

Poniendo los enlaces

Ahora que hemos preparado nuestro modelo y controlador pasaremos a crear los enlaces que permiten a los usuarios darse de alta, entrar, salir, o cambiar su perfil. De entrada crearemos el enlace “Registro”, que pondremos en un div en el fichero de layout de nuestra aplicación (/app/views/layouts/application.html.erb).

  <div id="user_nav">
    <%= link_to "Registro", new_user_path %>
  </div>
  

Como queremos que el enlace aparezca en el lado derecho de la página y además con un tamaño un poco menor, utilizaremos CSS para flotarlo modificando la hoja de estilos

  div#user_nav { float: right; font-size: 0.9em; }
  

Ya tenemos nuestro enlace de registro en todas las páginas de nuestra aplicacion.

El enlace “Registro” lleva a /users/new, así que nuestra próxima tarea es escribir el código que crea un nuevo usuario. Ya tenemos el controlador y la vista, y el código que nos hace falta es muy sencillo.

    def create
      @user = User.new(params[:user])
      if @user.save
        flash[:notice] = "Te has registrado correctamente."
        redirect_to root_url
      else
        render :action => 'new'
      end
    end
  

Este código de controlador es el estándar en REST. La acción new crea un objeto de usuario vacío, mientras que la acción create creará un nuevo usuario a partir de los parámetros enviados y lo guarda en la base de datos si es válido, mostrando otra vez el formulario new si no lo es.

El formulario de registro se utilizará cuando se registre o edite el perfil de un usuario, por lo que será mejor que lo pongamos en un parcial.

  <% title ("Nuevo usuario") %>
  <%= render @user %>
  

El código de la vista new.html.erb.

  <% form_for @user do |form| %>
  <%= form.error_messages %>
  <ol class="formList">
    <li>
      <%= form.label :username, "Nombre de usuario" %>
      <%= form.text_field :username %>
    </li>
    <li>
      <%= form.label :email, "Email" %>
      <%= form.text_field :email %>
    </li>
    <li>
      <%= form.label :password, "Clave" %>
      <%= form.password_field :password %>
    </li>
    <li>
      <%= form.label :password_confirmation, "Confirmación de clave" %>
      <%= form.password_field :password_confirmation %>
    </li>
    <li>
      <%= form.submit "Enviar" %>
    </li>
  </ol>
  <% end %>
  

El código _user.html.erb.

Ya podemos pulsar en el enlace “Registro” para ver nuestro formulario de alta. Si intentamos registrarnos sin rellenar ninguno de los campos, veremos que Authlogic proporciona ciertas validaciones automáticas para el modelo User.

Si rellenamos el formulario correctamente nos redirigirá a la página raiz de nuestro sitio con un mensaje diciendo que nos hemos dado de alta correctamente en la aplicación.

Inicio de sesión

Además del enlace a “Registro” queremos uno de “Entrar” de forma que un usuario registrado pueda iniciar una sesión. Para hacerlo con Authlogic necesitaremos crear otro modelo llamado UserSession que representa la sesión actual del usuario, lo que quiere decir que para iniciar la sesión sólo tenemos que crear un registro UserSession. Authlogic proporciona un script generador para crear este modelo.

  $ script/generate session user_session
      exists  app/models/
      create  app/models/user_session.rb
  

Este generador es muy sencillo y tan sólo crea el nuevo modelo UserSession. Si miramos ese modelo, veremos que es tan sólo una clase vacía que hereda de Authlogic::Session::Base, pero bastará con eso para gestionar toda la lógica de sesión.

  class UserSession < Authlogic::Session::Base
  end
  

Dado que el script no crea ningún controlador o vistas aún tenemos que crear el formulario de inicio de sesión. Podemos hacerlo de manera REST creando un controlador UserSessions y dándole acciones new, create y destroy para crear y destruir sesiones. Sólo tendremos una vista asociada a new, por lo tanto esa es la única acción que crearemos en el controlador.

  script/generate controller UserSessions new
  

Los tres métodos necesarios en el controlador son, otra vez, los que se verían para cualquier otro controlador. Para new, tan sólo creamos una nueva instancia de UserSession.

  def new
    @user_session = UserSession.new
  end
  

Para nuestra acción create crearemos un objeto UserSession a partir de los parámetros recibidos. Si el usuario es válido el objeto UserSession tambien lo será y se podrá guardar.

  def create
    @user_session = UserSession.new(params[:user_session])
    if @user_session.save
      flash[:notice] = "Has entrado en la aplicación."
      redirect_to root_url
    else
      render :action => 'new'
    end
  end
  

Por ultimo, en destroy simplemente tenemos que destruir el objeto UserSession actual. Obsérvese que no tenemos que encontrar la sesión por id dado que estamos destruyendo la del usuario actual.

  def destroy
    @user_session = UserSession.find
    @user_session.destroy
    flash[:notice] = "Successfully logged out."
    redirect_to root_url
  end
  

En la vista new tenemos que definir un formulario para que los usuarios puedan iniciar sesión.

Una vez más, tendremos que modificar nuestro archivo de rutas para que trate el controlador como un recurso y tendremos que añadir un par de rutas con nombre para dar URLs bonitas de registro e inicio de sesión.

  map.login 'login', :controller => 'user_sessions', :action => 'new'
  map.logout 'logout', :controller => 'user_sessions', :action => 'destroy'
  map.resources :user_sessions
  

Ya podemos volver al fichero de layout de nuestra aplicación y añadir el enlace de inicio de sesión.

  <div id="user_nav">
    <%= link_to "Registro", new_user_path %>
    <%= link_to "Entrar", login_path %>
  </div>
  

Ahora ya podemos entrar en la aplicación. Si proporcionamos un nombre de usuario o clave incorrectos el modelo UserSession se considera no válido y se nos mostrará un mensaje de error.

Si no es así habremos sido redirigidos a la página principal y tendremos una sesión iniciada.

Fin de sesión

No hemos terminado todavía. Después de que hayamos iniciado la sesión aún seguimos viendo los enlaces “Registro” y “Entrar” donde ahora deberíámos ver “Editar perfil” y “Salir”. Para cambiar estos enlaces tendremos que editar otra vez nuestro layout. No es necesario pasar un identificador de usuario a la acción edit porque siempre vamos a estar editando el usuario actual, así que simplemente basta con pasar :current. El método current_user que hemos empleado en la sentencia if aún no existe, así que lo vamos a escribir. Querremos que esté disponible en todos los controladores, así que irá en application_controller.rb.

  helper_method :current_user

  private
  def current_user_session
    return @current_user_session if defined?(@current_user_session)
    @current_user_session = UserSession.find
  end

  def current_user
    @current_user = current_user_session && current_user_session.record
  end
  

Hemos añadido dos métodos al controlador de aplicación. El primero, current_user_session, devuelve la sesión del usuario actual, y el segundo, current_user, devolverá el modelo User asociado al usuario actual. Haremos que current_user sea también un método helper de forma que podamos usarlo en nuestras vistas y layout.

Ahora cuando iniciemos la sesión veremos los enlaces correctos.

Tal y como hemos definido a ruta y la acción del controlador, el enlace “Salir” funcionará, pero para editar el perfil tendremos que modificar el controlador UsersController.

  def edit
    @user = current_user
  end

  def update
    @user = current_user
    if @user.update_attributes(params[:user])
      flash[:notice] = "Perfil actualizado correctamente."
      redirect_to root_url
    else
      render :action => 'edit'
    end
  end
  

Los métodos edit y update son un poco diferentes en el sentido de que en lugar de recuperar un modelo por su id tan sólo obtienen el usuario actual, utilizando el método current_user que acabamos de escribir en el controlador de aplicación.

Por ultimo, tenemos que poner el formulario del usuario en la vista de la acción edit (/app/views/users/edit.html.erb).

  <% title ("Editar Usuario") %>
  <%= render @user %>
  

Ya podemos editar nuestro perfil cuando tenemos sesión iniciada, lo que significa que ya emos implementado toda la funcionalidad que queríamos en nuestro sitio. Los usuarios ya se puedan registrar, iniciar y terminar sesión, así como editar su perfil.

Lecturas Adicionales

La funcionalidad de Authlogic va mucho más allá de lo que hemos visto en este episodio. here’s much more functionality available in Authlogic than we’ve shown in this episode. Para más información, véase la página de Github de Authlogic y la página de su aplicación de ejemplo. También existe la documentación RDoc como referencia.