この記事は devise、omniauth-facebook、omniauth-twitterのGemを使って、メールとFacebookとTwitterでログイン機能を作ります。
まずはFacebookとTwitter側の設定から始めます。
Facebook側の設定
アプリを作成URL:https://developers.facebook.com/apps/create
新規アプリを作成してから「Facebookログイン」を設定します。
Facebookログインの設定画面ではまず public_profile
をAdvanced Accesssに切り替えて、それから「有効なOAuthリダイレクトURI」に <ホスト>/users/auth/facebook/callback
を入力します。
設定のベーシック画面でアプリのデータ使用状況の確認を完了を開始してから、アプリID
とアプリシークレット
をコピーしときます。
Twitter側の設定
App detailsの設定の例は以下のようで、注意するところは二つ:
-
Enable Sign in with Twitter
をチェック -
Callback URLs
に<ホスト>/users/auth/twitter/callback
を入力
デフォルトはメール情報を取得できなくて、メール情報を取得するにはPermissionsタブでRequest email address from users
をチェックして保存する必要があります。
最後は Keys and tokensタブで API key
とApi secret key
をコピーしておきます。
ここまではFacebookとTwitterの設定が完了なので、次はソースコードに着手します!
Gem導入
gem 'devise'
gem 'devise-i18n' # 英語で使うなら不要
gem 'omniauth-rails_csrf_protection'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
deviseのインストール
rails g devise:install
User
というモデルでdeviseを作る
rails g devise User
カスタムのため、コントローラとビューと翻訳ファイルをコピーしておく
deviseのコントローラ作成
rails g devise:controllers users
deviseのビュー作成
rails g devise:views users
deviseの翻訳ファイル作成
rails g devise:it8n:locale ja
ビューのフォルダ名はdevise
ではなくusers
などであれば、deviseの翻訳ファイルを編集する必要があります
ja:
# ・・・省略
devise: &devise
# ・・・省略
users: *devise
deviseの設定
config.omniauth :facebook,
ENV['FACEBOOK_APP_ID'],
ENV['FACEBOOK_APP_SECRET'],
{
scope: 'email',
image_size: 'large',
locale: 'en' # 英語で情報を取得
}
config.omniauth :twitter,
ENV['TWITTER_CONSUMER_API_KEY'],
ENV['TWITTER_CONSUMER_API_SECRET_KEY'],
{
image_size: 'original',
lang: 'en' # 英語で情報を取得
}
config.mailer_sender = 'LANGMEMO <notification@langmemo.com>' # deviseから送信するメールのアドレス
config.scoped_views = true # カスタマイズのビューを使う場合
アカウント登録、ログイン、ログアウトなどのURLヘルパー:
= link_to 'アカウント登録', new_user_registration_path
= link_to 'ログイン', new_user_session_path
= button_to 'ログアウト', destroy_user_session_path, method: :delete, 'data-turbo': false
アカウント登録時のカスタムフィールドを追加する場合
devise_for :users, controllers: {
registrations: 'users/registrations'
}
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end
# If you have extra params to permit, append them to the sanitizer.
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
アカウント情報更新時に現在のパスワードを無くする場合
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
アカウント登録して、メールで確認URLをクリックしてから自動ログインしたい場合
devise_for :users, controllers: {
confirmations: 'users/confirmations'
}
protected
# The path used after confirmation.
def after_confirmation_path_for(resource_name, resource)
# super(resource_name, resource)
sign_in(resource)
root_path
end
Deviseのフォームで送信した後のリダイレクトにturbo
をfalse
にしたい場合
html: { 'data-turbo': false }
を入れる
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { 'data-turbo': false }) do |f| %>
ここまではメールでアカウント登録、ログインができるようになりました。
FacebookとTwitterログイン
devise_for :users, controllers: {
omniauth_callbacks: 'users/omniauth_callbacks'
}
devise :database_authenticatable, :registerable, :recoverable,
:rememberable, :validatable, :confirmable, :trackable,
:omniauthable # これを追加
class << self
def find_for_oauth(auth)
@user = User.find_or_initialize_by(uid: auth.uid, provider: auth.provider)
assign_info(auth)
attach_image(auth.info.image) if auth.info.image
@user.skip_confirmation!
@user.save!
@user
rescue StandardError => e
e.message
end
def assign_info(auth)
@user.uid = auth.uid
@user.provider = auth.provider
@user.name = auth.info.name
@user.email = auth.info.email
@user.password = Devise.friendly_token[0, 20]
end
def attach_image(image_url)
@user.image.attach(io: URI.parse(image_url).open, filename: "user_#{@user.id}_image")
# ファイルの一番上に require 'open-uri' が必要
end
end
def facebook
callback_from :facebook
end
def twitter
callback_from :twitter
end
private
def callback_from(provider)
@user = User.find_for_oauth(request.env['omniauth.auth'].delete_if { |k, _v| k == 'extra' })
if @user.instance_of?(User)
flash[:notice] = t('devise.omniauth_callbacks.success', kind: provider.to_s.capitalize)
sign_in_and_redirect @user, event: :authentication
else
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_path, alert: @user
end
end