【決断くん】Twitter認証機能&自動投稿機能の実装
現在作っているアプリ、決断くんにtwitter認証機能と自動投稿機能を実装してみました。
理由としては2つあります。
・決断くんのこだわりポイントの1つ、twitter自動投稿機能を実装するためには、twitter連携が不可欠だから。
・twitterやFacebookなどのAPIを扱えるようになりたかったから。
実装については公式のwikiと頼もしい先輩方のQiitaの記事を参考に行ったためあまり特筆することはないので、学んだことや少し詰まったところだけ備忘録としてまとめます。
参考にさせていただいたQiita記事
【Rails】SorceryでTwitter認証 - Qiita
【2019年版】RailsアプリからTwitterに更新内容を自動投稿!RailsとTwitterの連携機能を実装 - AUTOVICE
認証機能の実装
Userモデルのemail属性のnull: false制約を解除
Twitterにはemail登録をしていないユーザーもたくさんいるので、email属性がnull: falseのままだと登録段階でemailアドレスを引っ張ってこれずにバリデーションエラーが起こると予想される。
なので、email属性のnull: false制約を解除した。
#ChangeColumnNotnullマイグレーション内 class ChangeColumnToNotNull < ActiveRecord::Migration[6.0] def change change_column :users, :email, :string, null: true end end
null: true
でもつけるのかな?とか思ってたらほんとにそうでびっくり。null: true
をつけてrails db:migrateしてやることでnull: falseを上書きして解除できた。
null: false
を後付けすることはあっても解除することはなかなかないので使う機会は限られるかもしれないが、覚えておこう。
エラー【OAuth::Unauthorized 400 bad request】
トップ画面からTwitterログイン画面に遷移する際に起こった。
Debuggerを使ったり色々な記事やwikiを見てみたが解決せず、結構時間を取られた。結論としては、credentials.yml.encを正しく読み込めていない or 記述できていなかったせいでエラーが起こっていたと判明。
そのため非推奨ではあるが、いったんsorcery.rbにkeyをベタ書きで記述するとうまく動いた。
#エラーがでたコード config.twitter.key = Rails.application.credentials.dig(:twitter, :key) config.twitter.secret = Rails.application.credentials.dig(:twitter, :secret_key)
#credentials.yml.enc内(vi) twitter: key: '自分のAPI key' secret_key: '自分のAPI secret key'
Sorcery.rbのコードを下のように直書きにした。
#正常に動いたコード config.twitter.key = '自分のAPI key' config.twitter.secret = '自分のAPI secret key'
これについては明日原因究明して追記したいところ。
callback時にログインに失敗してしまう問題
#問題のコード def callback provider = params[:provider] if @user = login_from(provider) redirect_to root_path, success: "#{provider.titleize}でログインしました" else begin @user = create_from(provider) reset_session auto_login(@user) redirect_to root_path, success: "#{provider.titleize}でログインしました" rescue StandardError redirect_to root_path, danger: "#{provider.titleize}でのログインに失敗しました" end end end
なぜか必ずrescue StandardErrorに流れてしまっていた。
Debugger起動させて1つずつ処理を見ていくと、crypted_passwordが空になっているのが問題と判明。
(Twitter連携に取り掛かるまでは通常のログイン機能のままだったので当然だが、DBとモデル両方でpassword属性にnull: falseをかけていた。)
そこでemail同様、password属性のnull: falseを一旦外してみると見事ログイン成功!
正直、twitterで強制的に呟かれることで決断に強制力を持たせるのがこのアプリの醍醐味というかおもしろポイントなので、普通のログイン機能はもう削除しちゃっていいかな。。。
自動投稿機能の実装
Twitter developerへの登録や設定は全て終了していたので、こちらは意外なほどあっさりと実装が完了した。railsの偉大さを改めて実感。
実装できたのはdeveloperに登録しているtwitterアカウントへの呟き機能のみだった。ユーザーのアカウントに強制的に呟かせるには、個人のaccess_tokenとaccess_token_secretを取得する必要がある。一応できるらしいが、アカウントをのっとるようなものなので「twitterでシェア!」ボタンの実装だけに止めることに。一応developerアカウントに自動で呟く機能の実装方法は下記に残しておく。
choice_controllerのコード
自分の場合のコードはこんな感じに。
# choice_controller内 def create options = [] options.push(@choice.option_1, @choice.option_2, @choice.option_3, @choice.option_4, @choice.option_5) options.reject!(&:blank?) @choice.result = options.sample if params[:back] render :new elsif @choice.save # \rは改行のコード @client.update("#{current_user.name}は、\r#{@choice.title}に対して、\r#{@choice.result}ことを決めた!!!!") flash[:success] = 'この決断をtwitterに投稿しました。必ず実行してください。' redirect_to "/choices/result/#{@choice.id}" end end . . . private def twitter_client @client = Twitter::REST::Client.new do |config| config.consumer_key = "自分のAPI key" config.consumer_secret = "自分のAPI secret key" config.access_token = "自分のaccess token" config.access_token_secret ="自分のsecret access token" end end
エラー【NameError in ChoiceController#update uninitialized constant ChoiceController::Twitter】
上のコードで実際に動かした際に出たエラー。updateがうまく動いていない。
原因はものすごく単純だった。
gem 'twitter'
をインストールしていなかった。
凡ミスには注意。
今回の振り返り
とうとうこのアプリのこだわりポイントであるtwitter自動投稿機能を実装できました。
APIと聞くと自分の中では難しいイメージがあったので、無事に実装できて良かったです。
外部アプリケーションとの連携は、今やどのサービスにも導入されているので今回の経験はとても役に立つと思います。
また、最初にsorceryで通常のログイン機能を実装した後、twitter認証を追加したのですが、そのせいでカラムの変更やモデルの変更などに時間を裂くことになりました。
当たり前のことですが、コーディングに入る前に、実装する機能やDB設計をしっかりと確立させておかないと面倒なことになると実感しました。
2021/01/25 追記
コンテストまでにデプロイを目指していたが、時間が足りず、仕事のため予選会に出れなくなってしまいました。基本機能が完成したこのタイミングでいったん実装を終了し、新しい知識を身に付けるため中断していた課題に戻ることにしました。