Rails7+omniauth-twitterでtwitterログイン

# はじめに
[現在開発している子育て情報サービス『コノタメ』](https://konotame.herokuapp.com/)にて、twitterのAPIを利用してログインする機能を実装しました。
手順を忘れないように記録しておきたいと思います。

### 環境
* Ruby 3.1.2
* Ruby on Rails 7.0.3
* 【gem】 sorcery 0.16.4
* 【gem】 turbo-rails 1.1.1
* omniauth-twitter 1.4.0

※ sorceryは利用しておりますが、sorceryのexternalモジュールは使用していません。

### 前提
[Simple Password Authentication](https://github.com/Sorcery/sorcery/wiki/Simple-Password-Authentication)にて、メールアドレス認証機能は実装済み

# 手順
## 1. Twitter APIの登録
[Developer Platform](https://developer.twitter.com/en)で、API申請をします。
これはたくさんの記事がありますので、割愛。
[こちらの記事](https://mitchieblog.com/twitter-api-apply/)とか、とても参考になります。
注意点は、Callback URIをきちんと入力しておくこと、アクセスレベルを"Essential"ではなく、"Elevated"にしておくこと。

## 2. Gemのインストール
ここから先は、
[こちらの記事](https://blog.tatehitolog.com/entry/2020/02/09/215835)を~~コピペ~~参考に。
```
# Gemfile

gem 'omniauth'
gem 'omniauth-twitter'
gem "omniauth-rails_csrf_protection"
gem 'dotenv-rails'
```
そして`bundle install`。

`gem "omniauth-rails_csrf_protection"`を入れるのは、下の記事を読みまして。

https://qiita.com/NT90957869/items/2a3ce18dedf93ccf2bdc


## 3. APIキーの登録
Consumer KeysのAPI Key and Secretを.envファイルに登録します。（.envファイルは.gitignoreに入れておく。）
```
# .env

TWITTER_KEY = 自分のAPI Key
TWITTER_SECRET = 自分のSecret
```
今回は、herokuにデプロイしていますので、herokuのSettings > Config VarsにもこちらのKeyやSecretを登録しておきます。

## 4. Userモデル追記

```
# migrationファイル

class SorceryCore < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :email,            null: false
      t.string :name, 　　　　　　　　　　　　　　　　　　　　　　　　null: false
      t.string :crypted_password
      t.string :salt

      t.timestamps                null: false
    end
  end
end
```
既にこのような形でUserモデルが作成されているので、以下をモデルファイルに追記。
```
# user.rb

class User < ApplicationRecord
  def self.find_or_create_from_auth(auth)
    uid = auth[:uid]
    name = auth[:info][:name]
    if auth[:info][:email].present?
      email = auth[:info][:email]
    else
      email = uid + '(好きなようにダミーを作る)' #入力しないとvalidationのため、user登録されないので、適当に作成。
    end

    self.find_or_create_by(email: email) do |user|
        user.name = name
        user.email = email
        user.password = (好きなように式などでダミーを作る) #入力しないとvalidationのため、user登録されないので、適当に作成。
        user.password_confirmation = user.password
    end
  end
end
```

## 5. Sessionコントローラー作成
```
# app/controllers/session_controller.rb

class SessionsController < ApplicationController
  skip_before_action :require_login

  def create
    @user = User.find_or_create_from_auth(request.env['omniauth.auth'])
    reset_session
    auto_login(@user)
    redirect_to root_path, notice: 'ログインしました'
  end

  def failure
    redirect_to root_url, notice: 'ログインに失敗しました'
  end
end
```
application_controller.rbに、`before_action :require_login`を設定しているので、`skip_before_action :require_login`を入れておかないと、ログインボタンを押しても、「ログインしてください」とだけメッセージがでてきて、一向にログインできません。
`auto_login(user)`はsorceryのメソッドです。

```
# config/routes.rb

Rails.application.routes.draw do
  get '/auth/:provider/callback', to: 'sessions#create'
  get '/auth/failure', to: 'sessions#failure'
end
```
ログアウトはsorceryで実装済みですので、今回は省いております。

## 6. ログインリンク作成
```
<%= button_to '/auth/twitter', method: :post, data: { turbo: false } do %><%= image_tag "/assets/sign-in-with-twitter-gray.png.twimg.1920.png" %><% end %>
```
実はここが一番苦労したところです。
ボタンを押しても押しても、画面遷移しないわけです。
何日も悩んでいたところに出会った記事が、[こちら](https://zenn.dev/batacon/articles/e9b4a88ede2889)！！
ふむふむ、、、rails7では、`link_to`のときに、`method: :post`が効かないことは知っていたので、`button_to`を使ってはいました。
しかし、さらに、`data: { turbo: false }`が必要だったようです！！
turbo-railsを利用されている方はご注意ください。

# おわりに
最初、sorceryのexternalモジュールを試してみたのですが、そうしたらAuthenticationデータがログインごとに作成されて困ってしまい、結局諦めることになりました。続いて、今回のomniauthを使うことにしたのですが、401エラーが出たり、302で終了したりして、何日も悩み、諦めかけていたのですが、たくさんの記事に救われ、今回ログイン機能を実装することができました！
この記事がどなたかのお役に立てればうれしいです。
また、何かご指摘がございましたら、コメントいただけるとうれしいです。