Login y Signup en Ruby On Rails

Cuando desarrollo un login de usuarios en Ruby On Rails, no suelo utilizar ningún tipo de gema. Éstas normalmente tienen muchas más funcionalidades de las necesarias, así que prefiero aligerar el proceso desarrollándolo por mí mismo. La forma de resolverlo se basa en el libro de de Michael Hartl. El capítulo concreto lo podéis leer aquí.. Sin embargo trataré de explicarlo de forma resumida aquí.

Rails

Añadir gemas

Antes de nada tenemos que añadir un par de gemas a nuestro fichero Gemfile. Después las instalaremos con bundle install . Son dos gemas muy sencillas que nos permitirán aplicar un cifrado a los datos (por seguridad) y poder validar sintácticamente el email introducido en el formulario.

gem 'bcrypt', '~> 3.1.7'
gem 'email_validator'


Creamos un modelo para Usuario.

Estos son los campos que hay que añadir: name, email, passworddigest, tokendigest.


# ejecutar esto en terminal
rails g model User name email:index password_digest token_digest
rake db:migrate

# añadir este código al modelo de Usuario
class User < ActiveRecord::Base
  validates :email, presence: true, uniqueness: true, email: true
  validates :password, presence: true, length: { minimum: 8 }
  has_secure_password # esto hará uso de la gema que gemos instalado antes
end


Creamos el controlador para el usuario

El controlador de usuario es el siguiente:


 class UsersController < ApplicationController
   def new
     @user = User.new
   end
   def create
     @user = User.new(user_params)
     if @user.save
       log_in(@user)
       redirect_to user_path
     else
       flash[:alert] = @user.errors.full_messages
       render :new
     end
   end

   private
     def user_params
       params.require(:user).permit(:name, :email, :password, :password_confirmation)
     end
 end


Creamos el controlador para gestionar la sesión

Luego crearemos las vistas, que serán muy sencillas. De momento el código del controlador es el siguiente:


 class SessionsController < ApplicationController
   def new
   end

   def create
     user = User.find_by(email: params[:session][:email])
     if user && user.authenticate(params[:session][:password])
       log_in(user)
       redirect_to user_path
     else
       render :new
     end
   end

   def destroy
     log_out if logged_in?
     redirect_to root_path
   end
 end


La vista para el formulario de login:

<h2>Iniciar sesion</h2>

<%= form_for(:session, url: login_path ) do |f| %>
  Email: <%= f.email_field :email %> <br>
  Password: <%= f.password_field :password %> <br>
  <%= f.submit "Iniciar sesion" %>
<% end %>

Algunos helpers

Vamos a agregar estos helpers para gestionar las operaciones básicas de los usuarios. De esta forma los tenemos bien organizados en un sitio más centralizado que puede ser accedido por todos los controladores. Lo agregamos a applicationController mediante include SessionsHelper.

module SessionsHelper
  def log_in(user)
    session[:user_id] = user.id
  end

  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end

  def logged_in?
    !current_user.nil?
  end

  def authenticate_user
    redirect_to root_path unless logged_in?
  end

  def log_out
    session.delete(:user_id)
    @current_user = nil
  end
end

Modificar el fichero routes.rb


root "static#main"

get '/main' => "static#main"
get '/user' => "static#user"

get "/signup" => "users#new"
post "/signup" => "users#create"

get '/login' => "sessions#new"
post '/login' => "sessions#create"
delete '/logout' => "sessions#destroy"

resources :users

Es importante agregar también esto al controlador static:

before_action :authenticate_user, only: [:user]

Crear las vistas

Vista para Main

<h1>Bienvenido</h1>

<%= link_to "registrate", signup_path %>
<%= link_to "Iniciar sesion", login_path %>
<% if logged_in? %>
  <%= link_to "Perfil", user_path %>
<% end %>

Vista para user:


<h1>Bienvenido <%= @current_user.name %></h1>
<%= link_to "Cerrar sesion", logout_path, method: :delete %>

Este formulario ya funcionaría pero sin embargo se puede mejorar: podemos añadir un módulo para dar de alta al usuario, y soporte para cookies para que las sesiones no se cierren al cerrar el navegador. Pero lo mostraré en siguientes artículos modificando lo realizado ya sobre este código que os he mostrado.