Cómo construir un sistema de inicio de sesión discreto en Rails

Un sistema de inicio de sesión discreto es el que se sale del camino del usuario. Hará su aplicación más agradable y más pulida. Este artículo lo guiará a través del proceso de configuración de los inicios de sesión de los usuarios, y luego ajaxificará el proceso moviendo el formulario a un cuadro modal que se comunica con el servidor. Además, este artículo le mostrará cómo crear la configuración utilizando jQuery y Prototype para que pueda elegir su biblioteca favorita. Este artículo asume que tienes experiencia con Rails y jQuery o Prototype.


Puede usar Adman65 / nettuts para un inicio de sesión exitoso. Asegúrate de usar malas credenciales para que puedas ver cómo funciona todo.

Lo que estamos haciendo



Empezando

Vamos a comenzar por crear una aplicación ficticia que tenga una página pública y privada. La url raíz es la página pública. Hay un enlace de inicio de sesión en la página pública. Si el usuario inicia sesión correctamente, se redirige a la página privada. Si no, se redirigen de nuevo al formulario de inicio de sesión. La página privada muestra el nombre de usuario. Usaremos esto como punto de partida para ajaxificar el sitio..

El primer paso es usar el comando rails para generar una nueva aplicación, luego instalar y configurar authlogic.

$ cd en un directorio $ rails discreto-login

Añadir authlogic.

# /config/environment.rb config.gem 'authlogic'

Ahora instala las gemas.

$ sudo gem install gemcutter $ sudo gem tumble $ sudo rake gems: instalar

A continuación, cree un modelo de usuario y agregue las columnas authlogic necesarias a la migración..

$ ./script/generate model El usuario existe app / models / exista test / unit / exista test / fixtures / create app / models / user.rb create test / unit / user_test.rb create test / fixtures / users.yml create db / migrate create db / migrate / 20100102082657_create_users.rb

Ahora, agregue las columnas a la nueva migración..

clase CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.string :login, :null => false t.string: crypted_password,: null => false t.string: password_salt,: null => false t.string: persistence_token,: null => false t.timestamps end end def self.down drop_table: los usuarios finalizan end

Migrar la base de datos.

$ rastrillo db: migrar

Incluir authlogic en el modelo de usuario..

# /app/models/user.rb class User < ActiveRecord::Base acts_as_authentic end

Ahora podemos crear un usuario. Dado que esta es una aplicación de demostración, no se requiere la funcionalidad basada en web para registrarse. Así que abre la consola y crea un usuario:

$ ./script/console >> me = User.create (: login => 'Adman65',: password => 'nettuts',: password_confirmation => 'nettuts')

Ahora tenemos un usuario en el sistema, pero no tenemos manera de iniciar sesión o cerrar sesión. Necesitamos crear los modelos, controladores y vistas para esto. Authlogic tiene su propia clase para el seguimiento de inicios de sesión. Podemos usar el generador para eso:

# crea la sesión de usuario $ ./script/generate UserSession

Luego necesitamos generar el controlador que iniciará / cerrará la sesión de los usuarios. Puedes crear sesiones como cualquier otro recurso en Rails..

# crear el controlador de sesión $ ./script/generate controlador UserSessions

Ahora establece su contenido a:

# /app/controllers/user_sessions_controller.rb class UserSessionsController < ApplicationController def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.save flash[:notice] = "Login successful!" redirect_back_or_default user_path else render :action => : nuevo final fin fin

Se ve exactamente igual que un controlador que se generó a través de andamios. Ahora crea el controlador de usuarios que tiene contenido público y privado. Generar un controlador de usuarios. Dentro del controlador usaremos un filtro anterior para limitar el acceso a las áreas privadas. El índice de acción es público y el show es privado..

# crea el controlador de usuarios $ ./script/generate controladores de usuarios

Actualizar su contenido:

# /app/controllers/users_controller.rb class UsersController < ApplicationController before_filter :login_required, :only => : muestre def def end end def show @user = current_user end privado def login_required a menos que current_user flash [: error] = 'Debe estar conectado para ver esta página.' redirect_to new_user_session_path end end end end

Debes notar que current_user es un método no definido en este punto. Defina estos métodos en ApplicationController. Abre application_controller.rb y actualiza su contenido:

# clase de controlador de aplicación ApplicationController < ActionController::Base helper :all # include all helpers, all the time protect_from_forgery # See ActionController::RequestForgeryProtection for details # From authlogic filter_parameter_logging :password, :password_confirmation helper_method :current_user_session, :current_user private def current_user_session @current_user_session ||= UserSession.find end def current_user @current_user ||= current_user_session && current_user_session.user end end

En este punto, los modelos y los controladores están completos, pero las vistas no. Necesitamos crear vistas para un formulario de inicio de sesión y el contenido público y privado. Usaremos la joya de nifty-generators para crear un diseño básico.

$ sudo gem instala nifty-generators $ ./script/generate nifty_layout

Es hora de crear el formulario de inicio de sesión. Vamos a usar un parcial para esto porque en el futuro usaremos el parcial para procesar solo el formulario de inicio de sesión en el cuadro modal. Aquí está el código para crear el formulario de inicio de sesión. Es exactamente lo mismo que si estuvieras creando una publicación de blog o cualquier otro modelo..

# crea las vistas de inicio de sesión # /app/views/user_sessions/_form.html.erb <% form_for(@user_session, :url => user_session_path) hacer | formulario | %> <%= form.error_messages %> 

<%= form.label :login %> <%= form.text_field :login %>

<%= form.label :password %> <%= form.password_field :password %>

<%= form.submit 'Login' %> <% end %>

Render el parcial en la nueva vista:

# /app/views/user_sessions/new.html.erb <% title 'Login Please' %> <%= render :partial => 'form'%>

Crea algunas páginas básicas para el contenido público y privado. La acción de índice muestra contenido público y muestra contenido privado.

# crea la página pública ficticia # /app/views/users/index.html.erb <% title 'Unobtrusive Login' %> 

Contenido público

<%= link_to 'Login', new_user_session_path %>

Y para la página privada:

# crea la página privada ficticia # /app/views/users/show.html.erb <% title 'Welcome' %> 

Hola <%=h @user.login %>

<%= link_to 'Logout', user_session_path, :method => : eliminar%>

Elimine el archivo /public/index.html e inicie el servidor. Ahora puedes iniciar sesión y salir de la aplicación..

$ ./script/server

Aquí hay algunas capturas de pantalla de la aplicación de demostración. La primera es la página pública..

Ahora el formulario de inicio de sesión

Y la pagina privada

Y finalmente, acceso denegado cuando intenta visitar http: // localhost: 3000 / usuario

El proceso de inicio de sesión de AJAX

Antes de continuar, debemos comprender cómo el servidor y el navegador trabajarán juntos para completar este proceso. Sabemos que necesitaremos usar un poco de JavaScript para el cuadro modal y el servidor para validar los inicios de sesión. Seamos claros sobre cómo va a funcionar esto. El usuario hace clic en el enlace de inicio de sesión, luego aparece un cuadro modal con el formulario de inicio de sesión. El usuario completa el formulario y se redirige a la página privada, o el cuadro modal se actualiza con un nuevo formulario de inicio de sesión. La siguiente pregunta es ¿cómo actualizar el cuadro modal o decirle al navegador qué hacer después de que el usuario envíe el formulario? Los rieles tienen bloques respond_to. Con respond_to, puede decirle al controlador que muestre contenido diferente si el usuario solicitó XML, HTML, JavaScript, YAML, etc. Así que cuando el usuario envía el formulario, el servidor puede devolver algún JavaScript para ejecutar en el navegador. Usaremos este render un nuevo formulario o una redirección. Antes de bucear más a fondo, repasemos el proceso en orden..

  1. El usuario va a la página pública.
  2. El usuario hace clic en el enlace de inicio de sesión
  3. Aparece el cuadro modal
  4. El usuario rellena el formulario.
  5. El formulario se envía al servidor.
  6. El servidor devuelve JavaScript para su ejecución
  7. El navegador ejecuta el JavaScript que redirige o actualiza el cuadro modal.

Ese es el nivel alto. Aquí está la implementación de bajo nivel.

  1. El usuario visita la página pública.
  2. La página pública tiene algunos JavaScript que se ejecutan cuando el DOM está listo y adjunta JavaScript al enlace de inicio de sesión. Ese javscript hace un XMLHTTPRequest (XHR a partir de ahora) al servidor para algunos JavaScript. El JavaScript establece el contenido del cuadro modal en el formulario HTML. El JavaScript también hace algo muy importante. Enlaza la acción de envío del formulario a un XHR con datos POST a la acción del formulario. Esto le permite al usuario seguir llenando el formulario de inicio de sesión dentro del cuadro modal.
  3. La caja modal ahora tiene la forma y requiere JavaScript
  4. El usuario hace clic en "Iniciar sesión"
  5. Se llama a la función submit () que realiza un POST XHR a la acción del formulario con sus datos.
  6. El servidor genera el JavaScript para el formulario o la redirección
  7. El navegador recibe el JavaScript y lo ejecuta. El navegador actualizará el cuadro modal o redirigirá al usuario a través de window.location.

Tomando un pico en el controlador AJAX Ready

Echemos un vistazo a la nueva estructura para el controlador UserSessions.

clase UserSessionsController < ApplicationController layout :choose_layout def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.save respond_to do |wants| wants.html  redirect_to user_path(@user_session.user)  wants.js  render :action => : redirigir # JavaScript para hacer el redireccionamiento final sino responder_para hacer | quiere | wants.html render: new wants.js # por defecto para create.js.erb end end end private def choose_layout (request.xhr?)? nil: 'aplicación' final fin

Como puedes ver la estructura es diferente. Dentro de if save, sino condicional, respond_to se usa para representar el contenido correcto. want.xx donde xx es un tipo de contenido. Por defecto, Prototype y jQuery solicitan texto / JavaScript. Esto corresponde a wants.js. Estamos listos para comenzar con la parte de AJAX. No utilizaremos ningún complemento, excepto los de cajas modales. Usaremos Facebox para jQuery y ModalBox para Prototype.

Prototipo

Rails ha incorporado soporte para Prototype. Los ayudantes de JavaScript de Rail son funciones de Ruby que generan JavaScript que utiliza Prototype. Esta técnica se conoce como RJS (Ruby JavaScript). Un ejemplo es remote_form_for que funciona como el estándar for_for agrega algunos JS vinculados a onsubmit que envían el formulario a su acción usando su método con sus datos. No usaré RJS en este artículo porque quiero demostrar JS de vainilla. Creo que al usar JS puro y eliminar a los ayudantes de JS, el artículo será más accesible para los desarrolladores con menos experiencia. Dicho esto, puede realizar fácilmente estos pasos utilizando los ayudantes de RJS / Prototype si lo desea..

Agregar prototipo a la aplicación es muy fácil. Cuando utiliza el comando rails, crea los archivos Prototype y scriptaculous en / public / JavaScripts. Incluirlos es fácil. Abra /app/views/layouts/application.erb y agregue esta línea dentro de la etiqueta de cabecera:

<%= JavaScript_include_tag :defaults %>

JavaScript_include_tag crea etiquetas de script para archivos predeterminados en / public / JavaScripts, lo más importante es prototype.js, effects.js, y application.js. effects.js es scriptaculous. application.js es un archivo que puede usar para mantener la aplicación específica de JS. Ahora necesitamos un plugin modal de caja. Vamos a utilizar esto. Es un plugin de caja modal muy agradable inspirado en OSX. La fuente está alojada en GitHub, por lo que tendrá que clonar y mover los archivos en el directorio de su proyecto. Por ejemplo:

$ cd code $ git clone git: //github.com/okonet/modalbox.git $ cd modalbox # mueva los archivos a los directorios correctos. # mueva modalbox.css a / public / stylesheets # mueva modalbox.js a / public / JavaScripts # mueva spinner.gif a / public / images

Ahora incluye las hojas de estilo y JavaScript en tu aplicación.

 <%= stylesheet_link_tag 'application' %> <%= stylesheet_link_tag 'modalbox' %> <%= JavaScript_include_tag :defaults %> <%= JavaScript_include_tag 'modalbox'%>

Ahora vamos a obtener nuestro enlace de inicio de sesión para abrir un modalbox. Para hacer esto, necesitamos agregar algún JavaScript que se ejecute cuando el DOM esté listo y adjunte el modalbox a nuestro enlace. Cuando el usuario haga clic en el enlace de inicio de sesión, el navegador realizará un GET para / user_sessions / new que contiene el formulario de inicio de sesión. El enlace de inicio de sesión utiliza el # selector de enlace de inicio de sesión. Actualice el enlace de inicio de sesión para utilizar el nuevo ID en /app/views/users/index.html.erb. Modifique la función link_to de esta manera:

<%= link_to 'Login', new_user_session_path, :id => 'login-link'%>

Eso nos da un # login-link. Ahora para el JavaScript para adjuntar un modalbox. Agregue este JS en /public/JavaScripts/application.js

document.observe ('dom: loaded', function () $ ('login-link'). observe ('click', function (evento) event.stop (); Modalbox.show (this.href, title : 'Login', ancho: 500););)

Hay algunos JS simples para cuando el usuario hace clic en el enlace y se abre un cuadro modal con el href del enlace. Consulte la documentación de modalbox si desea más personalización. Aquí hay una captura de pantalla:

Observe que dentro de la caja modal se ve muy similar a nuestra página estándar. Rails está utilizando el diseño de nuestra aplicación para todas las respuestas HTML. Dado que nuestros XHR desean fragmentos HTML, tiene sentido renderizar sin diseños. Vuelva a consultar el controlador de ejemplo. Introduje un método para determinar el diseño. Agregue eso a UserSessionsController para deshabilitar el diseño de XHR.

clase UserSessionsController < ApplicationController layout :choose_layout def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.save flash[:notice] = "Login successful!" redirect_to user_path else render :action => : new end end def destroy current_user_session.destroy flash [: notice] = "¡Cerrar sesión correctamente!" redirect_to root_path end private def choose_layout (request.xhr?)? nil: 'aplicación' final fin

Actualice la página y haga clic en el enlace para obtener algo como esto:

Rellene el formulario y vea que pasa. Si rellena el formulario con información incorrecta, se le redirige fuera del cuadro modal. Si inicias sesión correctamente eres redirigido normalmente. De acuerdo con los requisitos, el usuario debe poder completar el formulario una y otra vez dentro del cuadro modal hasta que inicie sesión correctamente. ¿Cómo podemos lograr esto? Como se describió anteriormente, necesitamos usar AJAX para enviar datos al servidor, luego usar JavaScript para actualizar el cuadro modal con el formulario o hacer una redirección. Sabemos que el modalbox hace un GET para HTML. Después de mostrar el modalbox inicial, necesitamos escribir JS que haga que el formulario se envíe por sí mismo al estilo AJAX. Esto permite que el formulario se envíe dentro del cuadro modal. Simplemente agregar este código después de llamar al cuadro modal no funcionará porque el XHR podría no haber terminado. Necesitamos usar el callback afterLoad de Modalbox. Aquí está el nuevo código:

document.observe ('dom: loaded', function () $ ('login-link'). observe ('click', function (evento) event.stop (); Modalbox.show (this.href, title : 'Login', ancho: 500, afterLoad: function () $ ('new_user_session'). Observe ('submit', function (event) event.stop (); this.request ();)) ;);)

La solicitud de formulario # es un método conveniente para serializar y enviar el formulario a través de un Ajax.Request al URL del atributo de acción del formulario, que es exactamente lo que queremos. Ahora puedes rellenar el formulario dentro del modal sin que se cierre. El lado del cliente ahora está completo. ¿Qué pasa con el lado del servidor? El cliente está enviando un POST que desea recuperar JS. El servidor debe decidir devolver JavaScript para actualizar el formulario o generar una redirección. En el UserSessionsController usaremos respond_to para manejar la solicitud de JS y un condicional para devolver el JS correcto. Comencemos por manejar el caso de inicio de sesión fallido. El servidor debe devolver JS que actualiza el formulario e indica al nuevo formulario que debe enviarse a través de ajax. Pondremos esta plantilla en /app/views/users_sessions/create.js.erb. Aquí está la estructura para la nueva acción de creación:

def create @user_session = UserSession.new (params [: user_session]) si @ user_session.save flash [: notice] = "¡Ingreso exitoso!" redirigir a ruta_de_usuario otra cosa responde_para hacer | quiere | wants.html render: new wants.js # create.js.erb end end end end

Ahora vamos a completar create.js.erb:

$ ('MB_content'). Update ("<%= escape_JavaScript(render :partial => 'form')%> "); Modalbox.resizeToContent (); $ ('new_user_session'). observe ('submit', function (event) event.stop (); this.request (););

Primero actualizamos el contenido para incluir el nuevo formulario. Luego redimensionamos el cuadro modal. A continuación le adjuntamos el formulario como antes. Voilla, puedes rellenar el formulario tantas veces como quieras..

A continuación tenemos que manejar el caso de redirección. Cree un nuevo archivo en /app/views/users_sessions/redirect.js.erb:

 window.location = ”<%= user_path %>”;

Ahora, actualice la acción de crear para manejar el proceso de redirección:

def create @user_session = UserSession.new (params [: user_session]) si @ user_session.save respond_to do | quiere | wants.html do flash [: notice] = "¡Inicio de sesión exitoso!" redirect_to user_path end wants.js render: redirect end else contest_to do | want | wants.html render: new wants.js # create.js.erb end end end end

¡Y eso es! Ahora intente iniciar sesión con las credenciales correctas y será redirigido a la página privada. Para obtener más información, intente agregar una rueda giratoria y una notificación que indique al usuario que el formulario está enviando o que se está redirigiendo. La aplicación todavía funciona si el usuario tiene JavaScript desactivado también.

jQuery

Como ya he cubierto el proceso de Prototipo, no entraré en el mismo detalle que antes. En su lugar, me moveré rápidamente describiendo el JavaScript alternativo para agregar a la aplicación. La versión de jQuery tendrá exactamente la misma estructura que la versión Prototype. Todo lo que necesitamos cambiar es lo que está en application.js, create.js.erb, y el JavaScript / css incluye.

Lo primero que tenemos que hacer es descargar jQuery y Facebox. Mueva jQuery a / public / JavaScripts como jquery.js. Para facebox, mueva las imágenes a / public / images /, las hojas de estilo a / public / stylesheets, y finalmente las JS a / public / JavaScripts. Ahora actualice /app/views/layouts/application.html.erb para reflejar los cambios:

 <%= h(yield(:title) || "Untitled") %> <%= stylesheet_link_tag 'facebox' %> <%= stylesheet_link_tag 'application' %> <%= JavaScript_include_tag 'jquery' %> <%= JavaScript_include_tag 'facebox' %> <%= JavaScript_include_tag 'application' %> 

Facebox viene con una hoja de estilo predeterminada que asume que tiene sus imágenes en / facebox. Tendrá que actualizar estos selectores en facebox.css así:

#facebox .b background: url (/images/b.png);  #facebox .tl background: url (/images/tl.png);  #facebox .tr background: url (/images/tr.png);  #facebox .bl background: url (/images/bl.png);  #facebox .br background: url (/images/br.png); 

Ahora adjuntamos facebox al enlace de inicio de sesión. Abre /public/JavaScripts/application.js y usa esto:

$ (document) .ready (function () $ ('# login-link'). facebox (loadingImage: '/images/loading.gif', closeImage: '/images/closelabel.gif',); );

Anulo la configuración predeterminada para que las imágenes reflejen la nueva ruta de la imagen. Inicie el servidor y diríjase a la página de índice. Debería ver un buen facebox con el formulario de inicio de sesión:

Lo siguiente que tenemos que hacer es configurar el formulario para que se envíe a través de AJAX. Al igual que antes, tendremos que usar devoluciones de llamada para ejecutar el código una vez que el cuadro modal esté listo. Usaremos el método de publicación de jQuery para la solicitud XHR. Facebox tiene un gancho de revelación posterior que podemos usar. aplicacion.js:

$ (document) .ready (function () $ ('# login-link'). facebox (loadingImage: '/images/loading.gif', closeImage: '/images/closelabel.gif',); $ (document) .bind ('reveal.facebox', function () $ ('# new_user_session'). submit (function () $ .post (this.action, $ (this) .serialize (), null, " script "); devolver falso;);););

Actualizar create.js.erb debería ser bastante fácil. Tenemos que actualizar el contenido del facebox y volver a verificar el formulario. Aquí está el código:

$ ('# facebox .content'). html ("<%= escape_JavaScript(render :partial => 'form')%> "); $ ('# new_user_session'). submit (function () $ .post (this.action, $ (this) .serialize (), null," script "); devuelve false; );

¡Y eso es! Aquí está el producto final:

Descargando el codigo

Puedes obtener el código aquí. Hay sucursales para cada biblioteca, por lo que puede consultar las versiones Prototype o jQuery. ¿Alguna pregunta, comentario, inquietud? Gracias de nuevo por leer!

  • Síganos en Twitter o suscríbase a Nettuts + RSS Feed para obtener los mejores tutoriales de desarrollo web en la web..