#環境
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
に対して以下を追記します
127.0.0.1 test.example.com
##4: Facebook認証をインストール(omniauth-facebook)
omniauth-facebookでやります。
omniauth-facebookのgithubもあるのですが、Deviseと連携させる場合は、Deviseのwikiを見た方が良いです。
やることはこんな感じ
- gem追加&bundle install
- omniauth用のproviderカラムとUIDカラムをUserモデルに追加
- Userモデル他を編集する
###4-1.gem追加&bundle install
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を使えるようにする
devise :omniauthable, :omniauth_providers => [:facebook]
ルーティングにcallbackとログアウトを追加する
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に書いてある通りでも良いのですが、私はシンプルにこんな感じでつくっています。
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
ログインリンクを追加する
<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) %>
##4: Deviseから不要な機能を削除する
Userモデルよりrememberableとtrackableを除く機能を削除。
先ほどのomniauthableとまとめるとこんな感じ。
devise :rememberable, :trackable, :omniauthable, omniauth_providers: [:facebook]
これでtest.example.comへアクセスすれば使えます。
#ユーザーモデルにnameカラムを追加する
手順はこんな感じ
- ユーザー名(name)カラムを追加する
- callbackを修正する
- ユーザー名編集画面を追加する
##1.ユーザー名(name)カラムを追加する
$ rails g migration AddNameToUsers name:string
$ rake db:migrate
##2.callbackを修正する
nameは編集される可能性があるので、find_by_or_createは使わずにfind_byとcreateを分ける。
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.ユーザー名編集画面を追加する
こんな感じで。
<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を使っていないのでユーザーの編集/削除は自前で実装する。
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
のみ。
resources :users, only: [ :edit, :update, :destroy ]
#Devise/registerableを使う場合
※Facebookによる登録とメールアドレスによる登録を併用する場合。
nameカラムを通すためにApplicationControllerにStrongParametersを追加しましょう。
(以下のコードはユーザー登録時とユーザー情報更新時に使う場合)
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
ルーティングも追加
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks', registrations: 'registrations' }
パスワードカラムを持たないとDevise経由でのユーザーは更新できないため、以下のメソッドを用意して(上書きして)おきましょう。
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によりメールアドレスを使わない認証を実装する方法