Integrando backbone.js e devise

Imagine o seguinte cenário: queremos implementar uma autenticação de usuário em um sistema rails que utiliza o devise. No front-end, estamos utilizando o backbone.js. Não é uma tarefa das mais complicadas, mas que requer alguns artifícios e um bom conhecimento da api do devise.

Devise é uma gem desenvolvida pela galera da plataformatec, que nos proporciona uma api completa e flexível para soluções de autenticação em rails. Sua api já abstrái para o desenvolvedor funcionalidades como encriptação senha, Omniauth, confirmação por email, esqueceu sua senha, bloqueio de conta, entre outras coisas.

O backbone.js é uma biblioteca javascript para criação de web apps. Ele nos auxilia a trabalhar em aplicações javascript de maneira desacoplada do DOM. Com estruturas de model, collections, views e templates, nos proporciona uma melhor organização e modularização do código javascript, facilitando a compreensão e a manutenção. Chega de javascript macarrônico. Backbone trabalha nativamente com REST, logo, casa muito bem com aplicações rails, restful.

Mão na massa

Como vamos usar o backbone para montar a interface com o usuário, não iremos utilizar os helpers do rails e do devise para montar os formulários. Em um projeto rails já pré-configurado com o devise, vamos instalar o backbone.js. Como sou preguiçoso, vou usar a gem banckone-on-rails.

Criei a view user_login.js para a tela como formulário de login:

BackDevise.Views.UserLogin = Backbone.View.extend({
  template: JST["users/login"],

  events: {
   "submit #user_login" : "auth"
  },

  initialize: function(){
    this.user = new BackDevise.Models.User();
    this.render();
  },

  auth: function(e){
    e.preventDefault();
    var $form = $(e.target);
    var self = this;

    $.ajax({
      url: "/users/sign_in.json",
      data: $form.serialize(),
      dataType: "json",
      type: "post",
      error: function(response){
        var result = $.parseJSON(response.responseText);
        $(".box-content").prepend("<div class="alert alert-error">"+ result['error'] +"</div>");
      },
      success: function(res){
        self.user.set(res);
        new BackDevise.Views.Dashboard({user: self.user});
      }
   })
 },

 render: function(){
   $(this.el).html(this.template());
   $("#main").html(this.el);
 }
})

Abaixo, a view do cadastro de usuário:

BackDevise.Views.UserRegistration = Backbone.View.extend({
  template: JST["users/signup"],

  events: {
    "submit #user_registration" : "signup"
  },

  initialize: function(){
    this.user = new BackDevise.Models.User();
    this.render();
  },

  signup: function(e){
    e.preventDefault();
    var $form = $(e.target);
    var self = this;

    $.ajax({
      url: "/users.json",
      data: $form.serialize(),
      dataType: "json",
      type: "post",
      error: function(response){
        var result = $.parseJSON(response.responseText);

        _(result.errors).each(function(errors,field) {
          var $controlGroup = $('.user_'+field);

          $('.user_'+field).addClass('error');
          _(errors).each(function(error, i) {
            $controlGroup.children(".controls").find("span.help-inline").remove();
            $controlGroup.children(".controls").append('<span class="help-inline">'+ error +'</span>');
          });
      });
    },
    success: function(res){
      self.user.set(res);
      window.location = "/";
    }
  })
 },

  render: function(){
    $(this.el).html(this.template());
  }
})

Como pode ser notado, não utilizei os métodos do backbone para fazer as requisições ajax. Ao invés disso, usei jquery puro, pois assim evitei utilizar mais uma dependência no projeto para mapear os atributos do formulário para o model user. No entanto, é recomendável utilizar os métodos do backbone, como model.save(), pois deixa o código bem mais semântico.

Pulo do gato

A partir da versão 2.2.0, o devise não aceita mais, por default, solicitações no formato json. Logo, é necessário setar o método respond_to no controller do devise. Para isso, adicionamos no application.rb o seguinte código:

  config.to_prepare do
    DeviseController.respond_to :html, :json
  end

Código no github: https://github.com/paulociecomp/backbone-devise

O que tu achas?

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s