質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.10%

SNS認証プラグインにおけるuninitialized constantエラー

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,507

s.k

score 266

今、開発中のサイトでSNS認証機能を実装したいです。
ユーザー登録時パスワードが不要になったりとユーザーにも運営側にもメリットがあるとわかりましたので取り組んでいます!

前提・実現したいこと

twitter認証を実装したい。

facebook認証はなんとかできました。
下記の記事のコードをほぼそのまま利用させてもらってます。

Devise+OmniAuthでQiita風の複数プロバイダ認証

発生している問題・エラーメッセージ

新規ユーザー登録画面上に、「twitterでログインする」リンクを作成しました。
リンクを押すと、下記画面に遷移し、数秒後にエラーが発生します。

【遷移先画面】
イメージ説明

【エラー内容】

NameError in OmniauthCallbacksController#twitter
uninitialized constant OAuthPolicy::Twitter

調べたところ、モデル名がRailの記法に合っていない場合に発生するエラーであると書いてありました。ただ、どうあっていないのかがよくわかりません…

該当のソースコード

流れはこのようになっています。

app/controllers/omniauth_callbacks_controller.rb:10:in `callback_for_all_providers'
app/helpers/o_auth_service/get_o_auth_user.rb:7:in `call'
app/models/social_profile.rb:9:in `find_for_oauth'
app/models/social_profile.rb:17:in `save_oauth_data!'
app/c:34:in `policy'←★エラー箇所★

【app/models/social_profile.rb:34:in `policy'】

32 def policy(provider, auth)
33     class_name = "#{provider}".classify
34      "OAuthPolicy::#{class_name}".constantize.new(auth) ←★OAuthPolicyをヘルパーで呼び出す際にエラーが起きている模様…★
35 end

以下、関連ヘルパーのコードです。 2つとも同じファイルに入っています。

★追加部分★

【app/helpers/o_auth_service/o_auth_policy.rb】★本件のエラー原因だと思われるヘルパー★

★追加部分★

module OAuthPolicy
  class Base
    attr_reader :provider, :uid, :name, :nickname, :email, :url, :image_url,
                :description, :other, :credentials, :raw_info
  end

  class Facebook < OAuthPolicy::Base
    def initialize(auth)
      @provider    = auth["provider"]
      @uid         = auth["uid"]
      @name        = auth["info"]["name"]
      @nickname    = ""
      @email       = ""
      @url         = "https://www.facebook.com/"
      @image_url   = auth["info"]["image"]
      @description = ""
      @credentials = auth["credentials"].to_json
      @raw_info    = auth["extra"]["raw_info"].to_json
      freeze
    end
  end

  class Twitter < OAuthPolicy::Base
    def initialize(auth)
      @provider    = auth["provider"]
      @uid         = auth["uid"]
      @name        = auth["info"]["name"]
      @nickname    = auth["info"]["nickname"]
      @email       = ""
      @url         = auth["info"]["urls"]["Twitter"]
      @image_url   = auth["info"]["image"]
      @description = auth["info"]["description"].try(:truncate, 255)
      @credentials = auth["credentials"].to_json
      @raw_info    = auth["extra"]["raw_info"].to_json
      freeze
    end
  end
end

【app/helpers/o_auth_service/get_o_auth_user.rb】

module OAuthService
  class GetOAuthUser

    def self.call(auth)
      # 認証データに対応するSocialProfileが存在するか確認し、なければSocialProfileを新規作成。
      # 認証データをSocialProfileオブジェクトにセットし、データベースに保存。
      profile = SocialProfile.find_for_oauth(auth)
      # ユーザーを探す。
      # 第1候補:ログイン中のユーザー、第2候補:SocialProfileオブジェクトに紐付けされているユーザー。
      user = current_or_profile_user(profile)
      unless user
        # 第3候補:認証データにemailが含まれていればそれを元にユーザーを探す。
        user = User.where(email: email).first if verified_email_from_oauth(auth)
        # 見つからなければ、ユーザーを新規作成。
        user ||= find_or_create_new_user(auth)
      end
      associate_user_with_profile!(user, profile)
      user
    end

    private

      class << self

        def current_or_profile_user(profile)
          user = User.current_user.presence || profile.user
        end

        # 見つからなければ、ユーザーを新規作成。emailは後に確認するので今は仮のものを入れておく。
        # TEMP_EMAIL_PREFIXを手掛かりに後に仮のものかどうかの判別が可能。
        # OmniAuth認証時はパスワード入力は免除するので、ランダムのパスワードを入れておく。
        def find_or_create_new_user(auth)
          # Query for user if verified email is provided
          email = verified_email_from_oauth(auth)
          user = User.where(email: email).first if email
          if user.nil?
            temp_email = "#{User::TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com"
            user = User.new(
              username: auth.extra.raw_info.name,
              email:    email ? email : temp_email,
              password: Devise.friendly_token[0,20]
            )
            # email確認メール送信を延期するために一時的にemail確認済みの状態にする。
            user.skip_confirmation!
            # email仮をデータベースに保存するため、validationを一時的に無効化。
            user.save(validate: false)
            user
          end
        end

        def verified_email_from_oauth(auth)
          auth.info.email if auth.info.email && (auth.info.verified || auth.info.verified_email)
        end

        # ユーザーとSocialProfileオブジェクトを関連づける。
        def associate_user_with_profile!(user, profile)
          profile.update!(user_id: user.id) if profile.user != user
        end
      end
    end
end

試したこと

①実は、このエラーの前にも同種のエラーが起きました。
その際は、ネットに記事が落ちていましたので、それを参考にし解決できました。
Ruby on Rails、Controllerからhelpersフォルダのクラスを使おうとするとuninitialized constantが発生する。

②、①ではヘルパーのフォルダ名を変更し、ヘルパー自身の名前も変更すると解決できたので、今回も同様にo_auth_policyをget_auth_policyに変更したり、別ファイルを作りそこにこのヘルパーを収納してみたりしました。ですが、できませんでした。

以上です。
よろしくお願いします((+_+))

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hana-da

    2016/11/04 15:17

    o_auth_service/o_auth_policy.rb はどこに置いてありますかね? これも app/ からの path で書いてほしいです。

    キャンセル

  • s.k

    2016/11/04 15:27

    hana-daさん お疲れ様です。★追加部分★に書きました!もし違っていればご指摘お願いします。

    キャンセル

回答 1

checkベストアンサー

+1

お疲れの hana-da ですw

app/helpers/o_auth_service/o_auth_policy.rb を app/helpers/o_auth_policy.rb にすればいいような気がします。


サーバーの再起動はしましたよね?
それでダメなら分けてみますか。。。。(helpersに置いてあるのもちょっと気になりますが。。。。)

app/helpers/o_auth_policy/base.rb

module OAuthPolicy
  class Base
    attr_reader :provider, :uid, :name, :nickname, :email, :url, :image_url,
                :description, :other, :credentials, :raw_info
  end
end

app/helpers/o_auth_policy/facebook.rb

module OAuthPolicy
  class Facebook < OAuthPolicy::Base
    def initialize(auth)
      @provider    = auth["provider"]
      @uid         = auth["uid"]
      @name        = auth["info"]["name"]
      @nickname    = ""
      @email       = ""
      @url         = "https://www.facebook.com/"
      @image_url   = auth["info"]["image"]
      @description = ""
      @credentials = auth["credentials"].to_json
      @raw_info    = auth["extra"]["raw_info"].to_json
      freeze
    end
  end
end

app/helpers/o_auth_policy/twitter.rb

module OAuthPolicy
  class Twitter < OAuthPolicy::Base
    def initialize(auth)
      @provider    = auth["provider"]
      @uid         = auth["uid"]
      @name        = auth["info"]["name"]
      @nickname    = auth["info"]["nickname"]
      @email       = ""
      @url         = auth["info"]["urls"]["Twitter"]
      @image_url   = auth["info"]["image"]
      @description = auth["info"]["description"].try(:truncate, 255)
      @credentials = auth["credentials"].to_json
      @raw_info    = auth["extra"]["raw_info"].to_json
      freeze
    end
  end
end

こむずかしいですが 定数の自動読み込みと再読み込み に通常必要な事はだいたい書いてあります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/04 15:48

    試してみましたが、同様のエラー表示がでました( ;∀;)
    【uninitialized constant OAuthPolicy::Twitter】
    です…

    キャンセル

  • 2016/11/04 15:59 編集

    hana-daさん、すいません。サーバーの再起動していませんでした。
    再起動後に試したところ、違うエラーが出てきたので、
    先程のエラーは解決できたと思います!

    エラー内容は
    【NoMethodError in OmniauthCallbacksController#twitter】
    【undefined method `skip_confirmation!' for #<User:0x0000000533c340>】

    ちなみに、出たエラーはこんなんです!
    今から取り組んでみたいと思います!

    このファイルはhelpersにはおかない方がいいんですか!

    キャンセル

  • 2016/11/04 16:02

    app/helpers は慣例的には view helper を置く場所ですね。

    キャンセル

  • 2016/11/04 16:07

    そうですよね( ;∀;)
    移動先見つけます。
    どうしてapp/helpersに置かれているか調べてみます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる