Help us understand the problem. What is going on with this article?

Rails5でFacebookログイン実装する

More than 1 year has passed since last update.

はじめに

今作っているアプリケーションでFacebookログインすることにしたので、調べながら実装した。
先人の記事とREADMEを読みながらすすめると割りとすぐにできたので人の優しさに感謝

実装

Gemのインストール

まずは必要なGemのインストールを行う。
今回はdeviseとfacebook-oauthを使って実装するのでこの2つをGemfileに追加する。

gem 'devise'
gem 'omniauth-facebook'

追加したらbunldeを実行する

$ bundle

deviseの設定ファイルを生成する

それでは、deviseの設定ファイルなどを生成する。
ターミナルで以下を実行する。

$ rails g devise:install

deviseのモデルを生成する

今回はUserモデルを作成した。

$ rails g devise user

生成されたマイグレーションファイルで管理したいユーザーのカラムを追加する。
あと、このカラムは必須なので忘れずに追加する。

t.string :provider
t.string :uid

マイグレーションファイルの編集が済んだらmigrateを実行する。

$ bundle exec rake db:migrate

Facebookにアプリを登録する

Facebookにアプリを登録してidとsecret_idをもらってくる。

ここにアクセスして自分のアプリを登録する。
https://developers.facebook.com/

deviseに設定

devise.rbにFacebookに登録したアプリのapp idとapp secretを登録する。
べたでの登録は危ないので、secrets.ymlとか環境変数とかに書いたのを読み込むようにすると良さげ。

config/initializers/devise.rb
Devise.setup do |config|
  config.omniauth :facebook, Rails.application.secrets.facebook[:app_id], Rails.application.secrets.facebook[:app_secret]

callback_urlが必要なこともある

config/initializers/devise.rb
config.omniauth :facebook,
    Rails.application.secrets.facebook[:app_id], Rails.application.secrets.facebook[:app_secret],
    callback_url: Rails.application.secrets.facebook[:callback_url]

モデルをomuniauthableにする

デフォルトではomuniauthを使えるようになっていないので、モデルに記述を追加して使えるようにする。

models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :omniauthable, omniauth_providers: [:facebook]
end

ルーティングを追加する

Facebookの認証後に処理を行うためのコールバックに必要なUルーティングを追加する。

config/routes.rb
devise_for :users,
    controllers: {
      omniauth_callbacks: 'users/omniauth_callbacks'
    }

リンクを表示する

Facebookの認証に飛ばすためのURLをもったリンクを任意のビューに追加する。
使っているテンプレートエンジンがSlimなもので、サンプルコードもSlimで失礼

views/layouts/_header.html.slim
= link_to 'Facebookでログイン', user_facebook_omniauth_authorize_path

コールバック時の処理を行う

コールバックが呼ばれたときに行う処理を記述する。
コントローラを用意する。
ルーティングでusers/omuniauth_coallbacksとしているので、app/controllers/users/omniauth_callbacks_controller.rbを追加する。

app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
end

コールバックは、プロバイダと同じ名前のアクションを定義してその中で実装する。

app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    @user = User.from_omniauth(request.env['omniauth.auth'])
    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
      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 root_path, alert: 'Facebook認証に失敗しました。'
  end
end

ソースコードについて

  1. request.env["omniauth.auth"]にOmniAuthがFacebookから取得した情報がハッシュとして登録されている。
  2. 有効なユーザーが見つかると、Deviseメソッド(sign_inまたはsign_in_and_redirect)でログインできる。
  3. ユーザーが永続化されていない場合は、OmuniAuthのデータをセッションに格納する。データは、deviseをキー名前空間として使用して保存する。deviseがdeviseで始まるキーのデータ尾を削除してくれるので便利。毎回自動的にリフレッシュされたセッションを得ることができる。

モデルにfrom_omniauthメソッドを定義する

app/controllers/users/omniauth_callbacks_controller.rbにfrom_omniauthメソッドがあるけど、まだ定義していないので、Userモデルにメソッドを定義する。
providerとuidで検索して、存在してればデータを取得し、なければ、データを保存するようにしている。
nameやavatarは該当するカラムが必要。

models/user.rb
def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.name = auth.info.name
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
      user.avatar = auth.info.image
    end
  end

最後に

自分はこれで上手くいった、、、、と思っている
もし上手く行かなかった場合や、間違いや、ここはこうした方がよいなどあったら教えてください。

参考

GitHub devise
GitHubdevise(Wiki OmuniAuth)
Devise+OmniAuthでユーザ認証を実装する手順
Fecebookログインが急にエラーになった時の対応

疑問

providerとuidで検索するならindex貼ったほうが良いのかな??

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away