LoginSignup
56
56

More than 5 years have passed since last update.

RailsでFacebook認証する(Devise + OmniAuth)

Posted at

環境

Rails 4.2.6
Devise 4.1.1
omniauth-facebook 3.0.0

やりたいこと

・Facebook認証をする
・Userモデルにnameカラムを追加する

Facebook認証する

1: 認証機能をインストール(Devise)

前も書きましたがdeviseの導入方法については詳しい記事がたくさんあるのでそちらを参考にしてください。
Qiita:Deviseの設定手順をまとめてみた。 その1 導入編
とか
Qiita:Rails 4.2 で ユーザー管理・認証 (devise)
とか。
まぁDeviseのGithubを参考にするのがベターだとは思います。

2: Facebook認証をするためのapp登録をする

Facebook Developersより登録し、「新しいアプリを追加」します。

3: ローカル環境からからアクセスするための設定。

設定>ベーシック>アプリドメインにローカル用の適当なドメインを追加します。→ test.example.com
Facebookログイン>有効なOAuthリダイレクトURIに先ほどのドメインを追加します。→test.example.com

開発環境のhostsファイルにlocalhostをtext.example.comとしてアクセスできるよう追記します。

Macなら/private/etc/hostsに対して、
Windowsならc:¥windows¥system32¥drivers¥etc¥hostsに対して以下を追記します

hosts
127.0.0.1       test.example.com

4: Facebook認証をインストール(omniauth-facebook)

omniauth-facebookでやります。
omniauth-facebookのgithubもあるのですが、Deviseと連携させる場合は、Deviseのwikiを見た方が良いです。

やることはこんな感じ
1. gem追加&bundle install
2. omniauth用のproviderカラムとUIDカラムをUserモデルに追加
3. Userモデル他を編集する

4-1.gem追加&bundle install

Gemfile
gem 'omniauth-facebook'
$ bundle install

4-2.omniauth用のproviderカラムとUIDカラムをUserモデルに追加

$ rails g migration AddOmniauthToUsers provider:string uid:string
$ rake db:migrate

4-3.Userモデル他を編集する

deviseのomniauthableを使えるようにする

app/models/user.rb
devise :omniauthable, :omniauth_providers => [:facebook]

ルーティングにcallbackとログアウトを追加する

routes.rb
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
  devise_scope :user do
    delete :sign_out, to: 'devise/sessions#destroy', as: :destroy_user_session
  end

callbackを作成する
Wikiに書いてある通りでも良いのですが、私はシンプルにこんな感じでつくっています。

/app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  include Devise::Controllers::Rememberable

  def facebook
    auth = request.env['omniauth.auth']
    user = User.find_or_create_by(
      provider: auth.provider,
      uid: auth.uid
    )

    remember_me(user)

    sign_in_and_redirect user, event: :authentication
  end

  def failure
    redirect_to root_path
  end
end

ログインリンクを追加する

/app/views/適当.html.erb
<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) %>

4: Deviseから不要な機能を削除する

Userモデルよりrememberableとtrackableを除く機能を削除。
先ほどのomniauthableとまとめるとこんな感じ。

app/models/user.rb
devise :rememberable, :trackable, :omniauthable, omniauth_providers: [:facebook]

これでtest.example.comへアクセスすれば使えます。

ユーザーモデルにnameカラムを追加する

手順はこんな感じ
1. ユーザー名(name)カラムを追加する
2. callbackを修正する
3. ユーザー名編集画面を追加する

1.ユーザー名(name)カラムを追加する

$ rails g migration AddNameToUsers name:string
$ rake db:migrate

2.callbackを修正する

nameは編集される可能性があるので、find_by_or_createは使わずにfind_byとcreateを分ける。

/app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  include Devise::Controllers::Rememberable

  def facebook
    auth = request.env['omniauth.auth']
    user = User.find_by(
      provider: auth.provider,
      uid: auth.uid
      ) || User.create(
      provider: auth.provider,
      uid: auth.uid,
      name: auth.info.name
    )

    remember_me(user)

    sign_in_and_redirect user, event: :authentication
  end

  def failure
    redirect_to root_path
  end
end

3.ユーザー名編集画面を追加する

こんな感じで。

app/views/users/edit.html.erb
<h2>プロフィールを編集する</h2>

<%= form_for(current_user, html: { method: :patch }) do |f| %>
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>

  <div class="actions">
    <%= f.submit '更新する' %>
  </div>
<% end %>

<h3>退会する</h3>

<%= button_to "退会する", user_path( current_user ), data: { confirm: "本当に退会してよろしいですか??" }, method: :delete %>

※registerableを使っていないのでユーザーの編集/削除は自前で実装する。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :set_user, only: [ :update, :destroy ]

  def edit
  end

  def update
    if @user.update( user_params )
      redirect_to root_path
    else
      render :edit
    end
  end

  def destroy
    if @user.destroy
      redirect_to root_path
      else
      render :edit
    end
  end

  private
  def set_user
    @user = User.find( params[:id] )
  end

  def user_params
    params.require(:user).permit( :name )
  end
end

ルーティングは:edit, :update, :destroyのみ。

routes.rb
  resources :users, only: [ :edit, :update, :destroy ]

Devise/registerableを使う場合

※Facebookによる登録とメールアドレスによる登録を併用する場合。

nameカラムを通すためにApplicationControllerにStrongParametersを追加しましょう。
(以下のコードはユーザー登録時とユーザー情報更新時に使う場合)

app/controllers/application_controller.rb
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << :name
    devise_parameter_sanitizer.for(:account_update) << :name
  end

ルーティングも追加

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

パスワードカラムを持たないとDevise経由でのユーザーは更新できないため、以下のメソッドを用意して(上書きして)おきましょう。

app/controllers/regitrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
  protected
  def update_resource(resource, params)
    resource.update_without_current_password(params)
  end
end

自前のviews/users/...html.erbは使わないので削除しておきましょう。

リンク

EasyRamble: Railsの認証プラグインDeviseでのStrongParametersについて
iii ThreeTreesLight: [rails][devise] devise userの更新対象追加 + current_password無し更新
Web屋さんのアレ: 【Facebook】Facebookアプリでlocalhostを指定する為のアレ【アプリ】
Simplie Post: RailsでDevise+OmniAuthによりメールアドレスを使わない認証を実装する方法

56
56
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
56