30
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Rails]SNSアカウントログイン機能の実装かつ既存userモデルと衝突しない方法

Last updated at Posted at 2018-11-28

#準備
※twitterとfacebookを例にする。基本的に同じパタンなので、googleなど他のSNSも簡単に適用できる。
※deviseは使わない
※私の既存user modelとsession controllerはRailsチュートリアルで書いたものと同じです

##developerアカウント作成、自分のAPPを追加

###Facebook
facebook developer (即時作成できる)
facebook_meitu_1.jpg
右上のメニューの中から追加したAPPを選択
Settings-BasicからAPP IDAPP SECRETを取得し、他のAPP情報も入力(ユーザ承認画面で表示される)
PRODUCTSのところでFacebook Loginを追加し、SettingsからValid OAuth Redirect URIs(https://domain_name/auth/facebook/callback) を入力
※セキュリティの関係で、facebookは今httpsのurlしか承認しないので、localhostは使えないです。実行してみたいならherokuにappをデプロイすることがおすすめです。※

###Twitter
twitter developer (審査するには少し時間かかる)
twitter_meitu_2.jpg
右上のメニューの中から追加したAPPを選択
Keys and tokensからConsumer API keys (API key+API secret key)を取得
App detailsからCallback URL
(http://localhost:3000/auth/twitter/callback 他複数追加可)を入力、他のAPP情報も入力(ユーザ承認画面で表示される)

##gem追加

Gemfile
gem 'omniauth'
gem 'omniauth-twitter'
gem 'omniauth-facebook'

##環境設定

./config/initializers/omniauth.rbというファイルを作成

omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['TWITTER_ID'], ENV['TWITTER_SECRET']
  provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET']
end

追加可能なオプションのパラメータは
omniauth-facebook (github)
omniauth-twitter (github)
で確認できる。
例えばこんな感じ:

omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['TWITTER_ID'], ENV['TWITTER_SECRET'],
  	{ :image_size => 'original', :authorize_params => { :lang => 'ja' } }
  provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET'],
  	{ display: 'page', image_size: 'normal' }
end

ENV['XXX']は環境変数です。XXXは自分で命名できます。

###localhostで設定したい場合
(特にwindowsユーザはこの方法が一番便利かなと思う)
./config/local_env.ymlというファイルを作成 (facebookはlocalhost実行不可なので省略)

local_env.yml
TWITTER_ID: '自分のAPP_ID'
TWITTER_SECRET: '自分のAPP_SECRET'

./.gitignoreというファイルに下記のコードを追加(自分のkeyをgithubなどで公開しないように)

.gitignore
/config/local_env.yml

###herokuで設定したい場合

$ heroku config:set TWITTER_ID=自分のAPP_ID
$ heroku config:set TWITTER_SECRET=自分のAPP_SECRET
$ heroku config:set FACEBOOK_ID=自分のAPP_ID
$ heroku config:set FACEBOOK_SECRET=自分のAPP_SECRET

#各ファイルを更新

##ルーティング

routes.rb
get 'auth/:provider/callback', to: 'sessions#create'

これが各developerアカウントのAPP設定で入力したredirect/callback URLになります

##ユーザモデル

user.rb
#auth hashからユーザ情報を取得
#データベースにユーザが存在するならユーザ取得して情報更新する;存在しないなら新しいユーザを作成する
def self.find_or_create_from_auth(auth)
  provider = auth[:provider]
  uid = auth[:uid]
  name = auth[:info][:name]
  image = auth[:info][:image]
  #必要に応じて情報追加してください
  
  #ユーザはSNSで登録情報を変更するかもしれので、毎回データベースの情報も更新する
  self.find_or_create_by(provider: provider, uid: uid) do |user|
    user.username = name
    user.image_path = image
  end
end
$ rails g migration add_columns_to_users
20181122113757_add_columns_to_users.rb
class AddColumnsToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :uid, :string
    add_column :users, :provider, :string
  end
end
$ rails db:migrate

##セッションコントローラ

sessions_controller.rb
def create
  auth = request.env['omniauth.auth']
  if auth.present?
    user = User.find_or_create_from_auth(request.env['omniauth.auth'])
    session[:user_id] = user.id
    redirect_back_or user
  else #既存パタン
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in user
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      redirect_back_or user
    else
      flash.now[:danger] = 'メールアドレスとパスワードの組み合わせは有効ではありません'
      render 'new'
    end
  end
end

##ユーザモデルのバリエーション
これだけじゃまだ動けない!
なぜなら、user modelでは色々なバリデーションがあるので、
self.find_or_create_by(provider: provider, uid: uid)という行でエラー発生。
※私のappではSNSアカウントでログインするならemailとpasswordがいらないので、バリデーションを以下のように修正した:

user.rb
validates :username, presence: true, unless: :uid? #他省略
validates :email, presence: true, unless: :uid?
has_secure_password validations: false
validates :password, presence: true, unless: :uid?

unless: :uid?というのは、
uidデータがあればusername, email, passwordデータなしでもUser.create()使えるようになります

##ビュー

###普通のテキストリンクでテストする場合
ログイン画面に追加

sessions/new.html.erb
<%= link_to "Twitterアカウントでログイン", "/auth/twitter" %>
<%= link_to "Facebookアカウントでログイン", "/auth/facebook" %>

###統一のボタンの場合
sns_meitu_4.jpg

Gemfile
gem 'bootstrap-social-rails'
gem 'font-awesome-rails'
custom.scss
@import "bootstrap-social";
@import "font-awesome";
sessions/new.html.erb
<p>
  <%= link_to '/auth/twitter', class: "btn btn-social btn-twitter" do %>
    <span class="fa fa-twitter"></span> Twitterアカウントでログイン
  <% end %>
</p>
<p>
  <%= link_to '/auth/facebook', class: "btn btn-social btn-facebook" do %>
    <span class="fa fa-facebook"></span> Facebookアカウントでログイン
  <% end %>
</p>
<p>
  <%= link_to '/auth/google_auth2', class: "btn btn-social btn-google" do %>
    <span class="fa fa-google"></span> Googleアカウントでログイン
  <% end %>
</p>
30
34
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
30
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?