Railsで Facebook ログインを実装してみた

#　Railsで作るFacebookログイン

こんにちは。今日はrailsで作るFacebookログイン機能を先日学んだのでメモ用としてここで記録していこうと思います。
では早速初めていきましょう。

全体を通して参考にしたサイト(https://freesworder.net/rails-facebook/)


##０.前提
前提として、私はプログラミング習いたてで学習中の身であるので、稚拙なコードや文章等散見されるかもしれませんが、気になる点、誤った表現等あればご指摘いただけると幸いです。

## 1. アプリケーションを作る。
まずFacebookログインを実装するためのアプリケーションと基本的なコントローラを作成していきます。
今回のアプリケーション名は「facebook_login」とします。

```:ターミナル
$ rails new facebook_login
$ cd facebook_login
$ rails g controller hello index
```

## 2. Deviseの導入
次に gem を使ってdeviseを入れていきます。

```:gemfile
gem 'devise'
```

```:ターミナル
$ bundle install
$ rails generate devise:install
$ rails generate devise:controllers users
$ rails generate devise user
$ rails db:migrate

```

## 3.利用するモジュールの編集
deviseを導入すると　app/models/user.rbファイルが生成され中身を見ると以下のようになっていると思います。

```:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end
```
この devise:　以降に記述されている :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable はモジュールというものでどのモジュールを利用するかはここで定義することができます。
それぞれ何をするためのモジュールなのかは以下のリンクを参照してみることができます。
https://github.com/plataformatec/devise
また上記を日本語訳したリンクも貼っておきます(ただし少し古い記事になりますが...)
https://qiita.com/gakkie/items/6ef70c0788c3cbff81ee#i18n

ここに :omniauthable　を追加しましょう。
以下のようになって入ればオッケーです。

```:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable
end
```

## 4.Omniauthでの認証

次にOmniauthでの認証を実装していこうと思います。

```:gemfile
gem 'omniauth'
gem 'omniauth-facebook'
```

```:ターミナル
$ bundle install
```

###　カラムの追加
Omniauthではuid（一意のID）とprovider（FacebookやTwitterなど）をカラムとして利用します。
またnameカラムとimageカラムも追加してFacebookから名前とプロフィール画像を引っ張ってこられるようにします。

```:ターミナル
$ rails g migration AddColumnsToUsers uid:string provider:string name:string image:string
$ rails db:migrate
```

## 5. Facebook APIキーの取得

以下のリンクからAPIキーを取得しましょう。

[Facebook Developers](https://developers.facebook.com/)

<img width="1435" alt="スクリーンショット 2018-10-12 4.36.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/301142/f5567938-0e75-1fb2-3286-c6d3e057417d.png">
右上にある「スタートガイド」ボタン（人によってはログインもしくはマイアプになっているかも）を押してログインを進める。
途中でメールアドレス(Contact Email)とアプリ名(Display Name)を入力するところに行き着くと思いますが、アプリ名は正直適当でいいです(私は　Makoto Shiraishi's first appにしました)。そこでCreateボタンを押しましょう。

作成が完了したら、設定より「Basic」→「Add Platform」(画面の一番下までスクロールしたら出てきます)→「Website」を選択する。
サイトURLにURLを入力する（例：http://localhost:3000/ ）。
そして「変更を保存」ボタンを押してください。

ここから先の内容はちょっと筆者自身完璧に理解していないので、どういうコードを書くかについて言及を留めておきます。
わかり次第更新しいこうと思いますので、ご了承ください...

##6.APIキーの非公開

先ほどFacebookのAPIを取得することができたと思いますが、この情報は非常に機密性が高く決して外部に漏らしてはいけない情報なので、このAPIキーが間違って公開されないような処理を施す必要があります。
のでこの節ではWebサービスを公開した時にAPIキーを公開しないようなコードを書いていくことにします。

参考にした記事(https://qiita.com/noraworld/items/bfa80811c9e30b4474af)

```:gemfile
gem 'dotenv-rails'
```

```:ターミナル
$ bundle install
```

次に「.env」というファイルをアプリケーションディレクトリ(appやdbやGemfileがあるディレクトリ)に作成します。
以下の図のようになっていればオッケーです。

<img width="1434" alt="スクリーンショット_2018-10-17_2_03_28.png" src="https://qiita-image-store.s3.amazonaws.com/0/301142/9c267a60-4ba5-7281-447a-f2504e59d892.png">

次に作成した「.env」ファイルに以下を入力します。

```:.env
FACEBOOK_ID='APP ID'
FACEBOOK_SECRET_KEY='APP Secret'
```
ここで'APP ID'と'APP Secret'は先ほどの[Facebook Developers](https://developers.facebook.com/)で取得したキーに書き換えておいてください（自分が取得したキーは絶対他言しないように！！）。
ので結果として以下のようになって入ればオッケーです。（数字は個々人によって変わります。）

```:.env
FACEBOOK_ID='123456789012345' #←この数字は人によって違います！！
FACEBOOK_SECRET_KEY='1a2s3d4f5g6h7j8k9l0a1s2d4f5g6h1q' #←この数字は人によって違います！！
```

　最後に隠しておきたいデータを定義した.envファイルをみんなに公開してしまっては意味が無いのでこのファイルは公開しないようにします。.gitignoreに下記を追加します。

```:.gitignore
# 省略

/.env
```

これでとりあえずOKです！

##7.APIキーの利用



config/initializers/devise.rbの259行目あたりに以下の記述がコメントアウトされていると思います

```:config/initializers/devise.rb
 # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
```
のでこの下の行に以下を追記してください。

```:config/initializers/devise.rb
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET_KEY']　 #←追加する部分はここ！
```

##8. Userモデルにfindメソッドを実装とUserコントローラにコールバック処理を実装

以下を該当のファイルの好きな場所にコピペします。

uidとproviderの組み合わせは一意であり、これによりユーザを取得する。
レコードに存在しない場合は作成する。

```:app/models/user.rb
class User < ActiveRecord::Base #ここはすでに記述されいてるのでコピペしなくていいです！


  # 省略


  def self.find_for_oauth(auth)
    user = User.where(uid: auth.uid, provider: auth.provider).first

    unless user
      user = User.create(
        uid:      auth.uid,
        provider: auth.provider,
        email:    auth.info.email,
        name:  auth.info.name,
        password: Devise.friendly_token[0, 20],
        image:  auth.info.image
      )
    end

    user
  end
end　#ここはすでに記述されいてるのでコピペしなくていいです！
```



```:app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController　#ここはすでに記述されいてるのでコピペしなくていいです！
  def facebook
    callback_from :facebook
  end

  private

  def callback_from(provider)
    provider = provider.to_s

    @user = User.find_for_oauth(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
      sign_in_and_redirect @user, event: :authentication
    else
      session["devise.#{provider}_data"] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end　#ここはすでに記述されいてるのでコピペしなくていいです！
```

　最後にconfig/routes.rbを見ると以下のようになっていると思います。

```:config/routes.rb
Rails.application.routes.draw do
  devise_for :users

  # 省略（人によって違う。）

end

```

これを以下のように書き換えてOAuthのコールバック用のルーティングを設定してください。

```:config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

  # 省略（人によって違う。）

end

```

以上です！

rails sを実行して

[localhost:3000/users/sign_up](localhost:3000/users/sign_up)
に飛んで処理を確認してみてください！！