Ir para conteúdo principal
Lucas Caton

Vídeo: Permita que usuários façam login no seu app Rails usando o Facebook

Lucas Caton

Lucas Caton

@lucascaton
Nesse novo screencast, vou ensinar como adicionar uma interessante funcionalidade ao seu app: autenticação usando o Facebook.
Para ficar mais interessante, usei um projeto real: o Easy Bills. O projeto usa Ruby e Ruby on Rails e adicionalmente, eu incluí a gem omniauth-facebook.

Abaixo, você encontra os arquivos que eu criei ou alterei no vídeo:
Gemfile:
ruby
gem 'omniauth-facebook'
app/assets/images/social-sign-in/facebook.svg:
xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
   width="35px" height="35px" viewBox="0 0 300 300" enable-background="new 0 0 266.893 266.895"
   xml:space="preserve">
<path id="f" fill="#FFFFFF" d="M182.409,262.307v-99.803h33.499l5.016-38.895h-38.515V98.777c0-11.261,3.127-18.935,19.275-18.935
  l20.596-0.009V45.045c-3.562-0.474-15.788-1.533-30.012-1.533c-29.695,0-50.025,18.126-50.025,51.413v28.684h-33.585v38.895h33.585
  v99.803H182.409z"/>
</svg>
app/assets/stylesheets/authentication.sass (ou app/assets/stylesheets/application.sass):
sass
@import 'modules/social-buttons'
app/assets/stylesheets/modules/social-buttons.sass:
sass
// https://github.com/vagnervjs/social-signin-btns

$services: google #DD4B39, facebook #3B5998, twitter #00ACED, microsoft #e3b30d, github #2a2a2a, foursquare #95c330, instagram #906248, linkedin #0b5ea3, evernote #5ca629, dropbox #1b73d1

.btn-si
  background-position: 1em
  background-repeat: no-repeat
  background-size: 2em
  border-radius: .5em
  border: none
  color: #fff
  cursor: pointer
  font-size: 1em
  line-height: 1em
  padding: 0 2em 0 4em
  text-decoration: none
  transition: all .5s

@each $service in $services
  .btn-#{nth($service, 1)}
    background-color: #{nth($service, 2)}

    &, &:hover, &:active
      background-image: image-url("social-sign-in/#{nth($service, 1)}.svg")
      color: #fff

    &:hover
      background-color: lighten(nth($service, 2), 10%)

    &:active
      background-color: darken(nth($service, 2), 10%)

.btn-si-a
  padding: 15px 15px 15px 65px !important
  font-family: arial

.smaller .btn-si-a
  padding-left: 40px !important
  font-size: 12px
app/controllers/users/omniauth_callbacks_controller.rb:
ruby
module Users
  class OmniauthCallbacksController < Devise::OmniauthCallbacksController
    def facebook
      @user = User.from_omniauth(request.env['omniauth.auth'])

      if @user.persisted?
        sign_in_and_redirect @user, event: :authentication # Throws if @user is not activated
        set_flash_message(:notice, :success, kind: 'Facebook') if is_navigational_format?
      else
        session['devise.facebook_data'] = request.env['omniauth.auth']
        redirect_to new_user_registration_url
      end
    end

    def failure
      redirect_to new_user_session_path
    end
  end
end
app/models/concerns/omniauthenticable.rb:
ruby
module Omniauthenticable
  extend ActiveSupport::Concern

  included do
    def self.from_omniauth(auth)
      existing_user = User.find_by(email: auth['info']['email'])

      if existing_user
        existing_user.update!(provider: auth.provider, uid: auth.uid)
        existing_user
      else
        where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
          user.email                 = auth.info.email
          user.password              = Devise.friendly_token[0, 20]
          user.password_confirmation = user.password
          user.name                  = auth.info.name
          user.photo                 = auth.info.image
          user.skip_confirmation!
        end
      end
    end

    def self.new_with_session(params, session)
      super.tap do |user|
        data = session['devise.facebook_data'] &&
          session['devise.facebook_data']['extra']['raw_info']

        user.email = data['email'] if data && user.email.blank?
      end
    end
  end
end
app/models/user.rb:
ruby
class User < ApplicationRecord
  include Omniauthenticable

  devise :omniauthable, omniauth_providers: %i[facebook]

  # etc
end
app/views/devise/sessions/new.html.haml:
haml
%hr.m-t-25
.m-b-10 or

.fg-line.m-b-10
  = link_to 'Sign in with Facebook', user_facebook_omniauth_authorize_path,
    class: 'btn btn-si btn-si-a btn-facebook'
config/initializers/devise.rb:
ruby
config.omniauth :facebook, 'FACEBOOK_APP_ID', 'FACEBOOK_APP_SECRET'
config/routes.rb:
ruby
devise_for :users, controllers: {
  omniauth_callbacks: 'users/omniauth_callbacks',
  # etc
}
db/migrate/20171204023306_add_omniauth_to_users.rb:
ruby
class AddOmniauthToUsers < ActiveRecord::Migration[5.1]
  def change
    add_column :users, :provider, :string
    add_column :users, :uid,      :string
  end
end