Rails+Deviseでgoogleログインするまで
 Author: ion

rails

deviseとは

deviseを使わないrailsプロジェクトは見たことがないくらい便利な認証系全部入りのgem
webサービスをやるときはできるだけパスワードを持ちたくないのでgoogle/facebook/twitterログインと合わせて使うことが多い。

Install

Gemfile

gem 'devise'
bundle install
rails g devise:install

Model

rails g devise user

できたマイグレーションファイルにこんな一画がコメントアウトされているが、外しておく。

## Trackable
t.integer  :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string   :current_sign_in_ip
t.string   :last_sign_in_ip
rails db:migrate

View

rails g devise:views users

Controller

rails g devise:controllers users

Route

route.rb

devise_for :users, :controllers => {
  :registrations => 'users/registrations',
  :sessions => 'users/sessions'   
} 

devise_scope :user do
  get "user/:id", :to => "users/registrations#detail"
  get "signup", :to => "users/registrations#new"
  get "login", :to => "users/sessions#new"
  get "logout", :to => "users/sessions#destroy"
end

i18n(日本語対応)

config/application.rb

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Myapp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2
    config.i18n.default_locale = :ja
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end

Gemfile

gem 'devise-i18n'
gem 'devise-i18n-views'
bundle install
rails g devise:views:locale ja

googleログイン

Google Developers Console登録

https://console.developers.google.com/project

  1. プロジェクトを作成
  2. [認証情報]からOAuth2.0クライアントIDを取得
  3. 承認済みのリダイレクトURIを下記に設定
    http://localhost:3000/users/auth/google/callback
  4. IDとsecretを控える

dotenv設定

開発環境ではdotenvでsecretとか管理するので入れておく。

Gemfile

gem 'dotenv-rails'
gem 'omniauth'
gem 'omniauth-google-oauth2'
bundle install

.env

GOOGLE_APP_ID=<your id>
GOOGLE_APP_SECRET=<your secret>

Userモデルに認証用カラム追加

googleに貰ったデータを入れとく用。
もうuserモデルは作成済みなのでカラムを追加する。

rails g migration addColumnToUsers

db/migrate/hogehoge_add_column_to_users.rb

class AddColumnToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :name, :string
    add_column :users, :provider, :string
    add_column :users, :uid, :string
    add_column :users, :token, :string
    add_column :users, :meta, :string
  end
end
rails db:migrate

モデル修正

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :trackable, :omniauthable, omniauth_providers: %i(google)

  protected
  def self.find_for_google(auth)
    user = User.find_by(email: auth.info.email)
    unless user
      user = User.create(name:     auth.info.name,
                        provider: auth.provider,
                        uid:      auth.uid,
                        token:    auth.credentials.token,
                        email:    auth.info.email,
                        password: Devise.friendly_token[0, 20],
                        meta:     auth.to_yaml)
    end
    user
  end
end

config修正

config/initializers/devise.rb

Devise.setup do |config|
  require 'devise/orm/active_record'
  config.omniauth :google_oauth2,
                  ENV['GOOGLE_APP_ID'], 
                  ENV['GOOGLE_APP_SECRET'], 
                  name: :google,
                  scope: %w(email) 
end

view作成

rails g controller home index

app/views/home/index.html.erb

<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

<% if user_signed_in? %>
<%= current_user.email %>
<% end %>

<%= link_to 'Signin with Google', user_google_omniauth_authorize_path %>

callback用routing作成

config/routes.rb

Rails.application.routes.draw do
  get 'home/index'
  devise_for :users, :controllers => {
    :registrations => 'users/registrations',
    :sessions => 'users/sessions',
    omniauth_callbacks: "users/omniauth_callbacks"
  } 
  
  devise_scope :user do
    get "user/:id", :to => "users/registrations#detail"
    get "signup", :to => "users/registrations#new"
    get "login", :to => "users/sessions#new"
    get "logout", :to => "users/sessions#destroy"
  end
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

callback用controller作成

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def google
    @user = User.find_for_google(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
      sign_in_and_redirect @user, event: :authentication
    else
      session['devise.google_data'] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end

動作確認

http://localhost:3000/home/indexにアクセスし、sign in with googleを押してみる。
ログインしたいアカウントを選択し、localhostにコールバックされる。
emailが無事表示されていればログイン成功。