【Rails】TwitterやFacebookで簡単ログインを実装

手順を自分用にメモがてら。deviseとomniauthを利用した簡単ログイン(Sign up)の実装方法です。

以下gifは以前RailsApp作った際の実装例です。

なお、この記事ではdeviseの導入からの手順を想定しています。

また、Twitter Developer Labsとfacebook for Developersのアカウントは持っている前提で話を進めていくので持っていない方は登録してください。

環境

手順1:必要なGemの追加

Gemfileに以下5つのgemを追加して

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.0'
gem 'rails', '~> 5.2.3'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
(中略)
gem 'devise' #追加
gem 'omniauth' #追加
gem 'omniauth-twitter' #追加
gem 'omniauth-facebook' #追加
gem 'dotenv-rails' #追加

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
(略)

ターミナルにて下記コマンドでインストールします。

$ bundle install

手順2:deviseのセットアップ

よくある普通の手順です。

$ rails g devise:install
$ rails g devise:views
$ rails g devise User
$ rails db:migrate

初めて使う人向けに一応(ある程度)詳しい説明も。

ターミナルにて下記コマンドを打ち込みます。

$ rails g devise:install

すると、下記のようなコメントが出てきていくつかのファイルが生成されます。

Running via Spring preloader in process 43388
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

上のコメントの数字の振られた手順を順番に実装していくとdeviseの使用が可能になります。

まずは1からです。config/environments/development.rbの最後に1行を追加します。

(中略)
       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end

次にターミナルにて下記のコマンドを実行します。

$ rails g controller home index

すると、app/controllersディレクトリにhome_controller.rbapp/viewsディレクトリにhomeディレクトリとその階層内にindex.html.erbができます。

次に2。config/routes.rbを開き、下記のようにします。

Rails.application.routes.draw do
  root "home#index" #追加
  (中略)
end

3ではapp/views/layouts/application.html.erbに下記のようにします。

(中略)
<body>
  <!-- ここから追加 -->
  <% if flash[:notice] %>
    <p><%= flash[:notice] %></p>
  <% end %>
  <% if flash[:alert] %>
    <p><%= flash[:alert] %></p>
  <% end %>
  <!-- ここまで追加 -->

  <%= yield %>
</body>

そして手順4のコマンドとモデルの作成のためのコマンドを上から順にターミナルで実行すればdeviseの実装は完了です。

$ rails g devise:views
$ rails g devise User
$ rails db:migrate

ユーザー登録のストロングパラメータ周り

app/controllers/application_controller.rbを下記のようにします。

class ApplicationController < ActionController::Base
(中略)
  #ここから追加
  before_action :configure_permitted_parameters, if: :devise_controller?
  protected
  #登録時と編集時に独自カラムのストロングパラメータ追加
    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: %i(name uid image provider))
      devise_parameter_sanitizer.permit(:account_update, keys: %i(name uid image provider))
    end
  #ここまで追加
end

deviseの日本語化

config/application.rbを下記のように編集します。

require 'rails/all'
Bundler.require(*Rails.groups)

module Config
  class Application < Rails::Application
    config.load_defaults 5.2
(中略)
    #ここから追加
    config.i18n.default_locale = :ja #日本語化する
    config.time_zone = 'Asia/Tokyo' #タイムゾーンを日本時間にする
    #ここまで追加
  end
end

続いてconfig/localesディレクトリにja.ymlを新規作成し、下記をコピペしてください。

ja:
  activerecord:
    models: #モデル名の日本語化
      user: "ユーザー"
    attributes:
      user: #ユーザーモデルのカラム名日本語化
        name: "名前"
        uid: "ID"
        image: "プロフィール画像"
        email: "メールアドレス"
        password: "パスワード"
  devise: #deviseに関するエラーメッセージ等の日本語化
    confirmations:
      confirmed: "アカウントが正常に確認されました。"
      send_instructions: "アカウントの確認方法をメールにてお送りします。"
      send_paranoid_instructions: "すでにメールアドレスが保存されている場合、アカウントの確認方法をメールにてお送りします。"
    failure:
      already_authenticated: "ログイン済みです。"
      inactive: "まだアカウントが有効化されていません。"
      invalid: "メールアドレスまたはパスワードが違います。ご確認ください。"
      locked: "このアカウントはロックされています。"
      last_attempt: "あなたのアカウントがロックされる前に、もう1つの試みを持っています。"
      not_found_in_database: "メールアドレスまたはパスワードが無効なものです。ご確認ください。"
      timeout: "一定時間が経過したため、再度ログインが必要です"
      unauthenticated: "ログインまたは登録が必要です。"
      unconfirmed: "本登録が必要です。"
    mailer:
      confirmation_instructions:
        subject: "アカウントの登録方法"
      reset_password_instructions:
        subject: "パスワードの再設定"
      unlock_instructions:
        subject: "アカウントのロック解除"
    omniauth_callbacks:
      failure: "%{reason}により、%{kind}から承認されませんでした。"
      success: "%{kind}から承認されました。"
    passwords:
      no_token: "このページにアクセスできません。URLをご確認ください。"
      send_instructions: "パスワードのリセット方法をメールにてお送りします。"
      send_paranoid_instructions: "すでにメールアドレスが保存されている場合、パスワードの再設定方法をメールにてお送りします。"
      updated: "パスワードを変更しました。"
      updated_not_active: "パスワードを変更しました。"
    registrations:
      destroyed: "アカウントを削除しました。またのご利用をお待ちしております。"
      signed_up: "アカウント登録を受け付けました。"
      signed_up_but_inactive: "アカウントは登録済みですが、有効化されていないため利用できません。"
      signed_up_but_locked: "アカウントは登録済みですが、ロックされているため利用できません。"
      signed_up_but_unconfirmed: "確認メールを登録したメールアドレス宛に送信しました。リンクを開いてアカウントを有効化してください。"
      update_needs_confirmation: "アカウント情報が更新されました。更新の確認メールを新しいメールアドレス宛に送信しましたので、リンクを開いて更新を有効化してください。"
      updated: "アカウントが更新されました。"
    sessions:
      signed_in: "ログインしました。"
      signed_out: "ログアウトしました。"
      Invalid email or password: "メールアドレスまたはパスワードが違います"
    unlocks:
      send_instructions: "アカウントのロック解除方法をメールにてお送りします。"
      send_paranoid_instructions: "アカウントが存在する場合、ロックの解除方法をメールにてお送りします。"
      unlocked: "アカウントのロックが解除されました。ログインしています。"
  errors:
    messages:
      already_confirmed: "は既に登録済みです。ログインしてください"
      confirmation_period_expired: "%{period}以内に確認する必要がありますので、新しくリクエストしてください。"
      expired: "有効期限切れです。新規登録してください。"
      not_found: "は見つかりませんでした。"
      not_locked: "ロックされていません。"
      not_saved:
        one: "以下のエラーで、この%{resource}を保存できません。"
        other: "%{count}個のエラーで、%{resource}を保存できません。"

モジュール追加

app/models/user.rbdeviseメソッドに:omniauthableを追加し、findメソッドを追記します。

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable

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

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

   private

   def self.dummy_email(auth)
     "#{auth.uid}-#{auth.provider}@example.com"
   end

end

手順3:omniauthのセットアップ

deviseはデフォルトではメールアドレスとパスワード用カラムしかなく、このままだとうまく動作しないのでターミナルにてUsersテーブルにカラムを追加します。

$ rails g migration AddColumnsToUsers name:string uid:string image:string provider:string
$ rails db:migrate

これでTwitterやFacebookから得た名前や画像などをデータベースへと格納できるようになります。

続いて、config/initializers/devise.rbを下記のようにします。

Devise.setup do |config|
(中略)
  config.omniauth :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET'],
  {
    :secure_image_url => 'true',
    :image_size => 'large'
   }
  config.omniauth :twitter, ENV['TWITTER_ID'], ENV['TWITTER_SECRET'],
  {
    :secure_image_url => 'true',
    :image_size => 'original'
  }
end

ここまで出来たら下記URLにアクセスし、各SNSのAPIキーを取得します。

次に.envファイルを新規作成し、下記のようにします。

TWITTER_ID: 'ここにTwitterのAPIキーをコピペ'
TWITTER_SECRET: 'ここにTwitterのシークレットキーをコピペ'
FB_ID: 'ここにfacebookのAPIキーをコピペ'
FB_SECRET: 'ここにfacebookのシークレットキーをコピペ'

手順4:コールバック処理の追加

app/controllersディレクトリにomniauth_callbacks_controller.rbを新規作成し、下記をコピペ。

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    callback_from :facebook
  end

  def twitter
    callback_from :twitter
  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

手順5:ルーティングを編集

config/routes.rbを下記のように編集。

Rails.application.routes.draw do
  root "home#index"
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
(中略)
end

動作確認

ここまできたらターミナルにてrails sを実行し、ローカルサーバーを立てて……

/users/sign_upにアクセスします。

試しにSign in with Twitterをクリックすると……

rootにリダイレクトされ、ログイン状態になりました。あとはcssでお化粧すればいい感じになります。

コメントを残す

メールアドレスが公開されることはありません。