Rails4.2とdeviseでFacebookとTwitter認証をテストした時に[Routing Error uninitialized constant]が発生
RailsとdeviseでFacebookとTwitter認証をテストしたらログアウト時にエラー
参考情報
RailsとdeviseでFacebookとTwitter認証を行う際に、以下のページを参考にした
Rails4 で Devise と OmniAuth で、Twitter/Facebook のOAuth認証と通常フォームでの認証を併用して実装 | EasyRamble
※ほとんどこのページを参考
環境
Rails 4.2.0
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
devise 3.4.1
omniauth 1.2.2
omniauth-facebook 1.4.1
omniauth-twitter 1.0.1
エラー内容
ログインはできるがログアウト時に以下のエラーが発生
Routing Error uninitialized constant Users::SessionsController
エラー対応
sessions_controllerでエラーが出ているので、sessions_controller.rbファイルを作成
devise_test/app/controllers/users/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController end
※中身は空でOK
これでログアウトエラーは解決!
作業内容まとめ
実行コマンド
プロジェクト作成
$ rails new devise_test
Gemfileに追記
project/Gemfile
... gem 'devise' gem 'omniauth', '~> 1.2.1' gem 'omniauth-twitter', '~> 1.0.1' gem 'omniauth-facebook', '~> 1.4.0' end
モジュールをインストール
$ cd devise_test $ bundle install
トップページを作成
$ rails g controller welcome index
deviseをインストール
$ rails generate devise:install create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. If you are deploying on Heroku with Rails 3.2 only, you may want to set: config.assets.initialize_on_precompile = false On config/application.rb forcing your application to not access the DB or load models when precompiling your assets. 5. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================
deviseのユーザモデルを作成
$ rails g devise User invoke active_record create db/migrate/20150103071332_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :users
deviseのユーザモデルにOmniAuth用のカラムを追加
$ rails generate migration AddOmniauthColumnsToUsers uid provider name invoke active_record create db/migrate/20150103071704_add_omniauth_columns_to_users.rb
migrationファイルを修正
class AddOmniauthColumnsToUsers < ActiveRecord::Migration def change add_column :users, :uid, :string, :string, null: false, default: "" add_column :users, :provider, :string, :string, null: false, default: "" add_column :users, :name, :string add_index :users, [:uid, :provider], unique: true end end
migrate実行
$ rake db:migrate == 20150103071332 DeviseCreateUsers: migrating ================================ -- create_table(:users) -> 0.0150s -- add_index(:users, :email, {:unique=>true}) -> 0.0017s -- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0008s == 20150103071332 DeviseCreateUsers: migrated (0.0178s) ======================= == 20150103071704 AddOmniauthColumnsToUsers: migrating ======================== -- add_column(:users, :uid, :string) -> 0.0015s -- add_column(:users, :provider, :string) -> 0.0011s -- add_column(:users, :name, :string) -> 0.0014s == 20150103071704 AddOmniauthColumnsToUsers: migrated (0.0043s) ===============
bootstrapのファイルコピー&定義
bootstrap-3.3.1-dist.zipのファイルを以下にコピー
devise_test/vendor/assets/javascripts/bootstrap.min.js
devise_test/vendor/assets/stylesheets/bootstrap.min.css
bootstrapの定義を追加
devise_test/app/assets/javascripts/application.js
//= require jquery //= require jquery_ujs //= require turbolinks //= require bootstrap.min //= require_tree .
devise_test/app/assets/stylesheets/application.css
*= require_tree . *= require_self *= require bootstrap.min */
user.rbの編集
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :omniauthable, :registerable, :recoverable, :rememberable, :trackable, :validatable def self.find_for_facebook_oauth(auth, signed_in_resource=nil) user = User.where(:provider => auth.provider, :uid => auth.uid).first unless user user = User.create(name: auth.extra.raw_info.name, provider: auth.provider, uid: auth.uid, email: auth.info.email, password: Devise.friendly_token[0,20] ) end user end def self.find_for_twitter_oauth(auth, signed_in_resource=nil) user = User.where(:provider => auth.provider, :uid => auth.uid).first unless user user = User.create(name: auth.info.nickname, provider: auth.provider, uid: auth.uid, email: User.create_unique_email, password: Devise.friendly_token[0,20] ) end user end # 通常サインアップ時のuid用、Twitter OAuth認証時のemail用にuuidな文字列を生成 def self.create_unique_string SecureRandom.uuid end # twitterではemailを取得できないので、適当に一意のemailを生成 def self.create_unique_email User.create_unique_string + "@example.com" end end
devise定義ファイルにFacebookとTwitterのアプリキーを登録
Devise.setup do |config| ... # When using omniauth, Devise cannot automatically set Omniauth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' # API key config.omniauth :facebook, "App ID", "App Secret" config.omniauth :twitter, "Consumer Key", "Consumer Secret" end
route.rbの設定
Rails.application.routes.draw do devise_for :users, :controllers => { :sessions => "users/sessions", :registrations => "users/registrations", :passwords => "users/passwords", :omniauth_callbacks => "users/omniauth_callbacks" } root to: 'welcome#index' end
トップ画面作成
<!DOCTYPE html> <html> <head> <title>deviseテスト</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> </head> <body> <header class="navbar navbar-default" role="navigation"> <div class="container"> <div class="navbar-header"> <%= link_to 'deviseテスト', root_path, class: 'navbar-brand' %> </div> <div class="navbar-text pull-right"> <% if user_signed_in? %> Logged in as <strong><%= current_user.name %></strong>. <%= link_to 'Edit profile', edit_user_registration_path, :class => 'navbar-link' %> | <%= link_to 'Sign out', '/users/sign_out', :method => :delete, :class => 'navbar-link' %> <% else %> <%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> | <%= link_to "Login", new_user_session_path, :class => 'navbar-link' %> | <%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) , :class => 'navbar-link' %> | <%= link_to "Sign in with Twitter", user_omniauth_authorize_path(:twitter) , :class => 'navbar-link' %> <% end %> </div> </div> </div> </header> <div class="container"> <% if notice %> <p class="alert alert-success"><%= notice %></p> <% end %> <% if alert %> <p class="alert alert-success"><%= alert %></p> <% end %> <%= yield %> </div> </body> </html>
OmniauthCallbacksControllerコントローラーを作成
以下のファイルを作成
devise_test/app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def facebook # You need to implement the method below in your model (e.g. app/models/user.rb) @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user) if @user.persisted? set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format? sign_in_and_redirect @user, :event => :authentication else session["devise.facebook_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end def twitter # You need to implement the method below in your model @user = User.find_for_twitter_oauth(request.env["omniauth.auth"], current_user) if @user.persisted? set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format? sign_in_and_redirect @user, :event => :authentication else session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra") redirect_to new_user_registration_url end end end
このままだとログアウト時にエラーが発生する
ログインはうまくいくが、ログアウトすると以下のエラーが発生する。
Routing Error uninitialized constant Users::SessionsController
SessionsControllerクラスを作成
エラー対応のため、以下のファイルを作成
devise_test/app/controllers/users/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController end
今回作成したプロジェクトは以下
yuriken27/rails_devise_test · GitHub