使用 Devise / Omniauth 成功验证后 CallbacksController#facebook 中的 RuntimeError Rails
RuntimeError in CallbacksController#facebook after successful authentication with Devise / Omniauth Rails
我正在使用 omniauth facebook gem 进行设计以构建注册系统。用户可以使用电子邮件注册或使用他们的 Facebook 帐户连接。
如果一个邮箱注册的用户使用facebook账号登录,我会检查邮箱地址是否已经注册并连接这两个账号,然后让用户登录。
整个场景已经可以运行了。使用 facebook 的新 omniauth 数据更新用户条目。我得到这个错误,当 facebooks 发送回调时(来自 facebook 的数据已成功保存到 db):
RuntimeError in CallbacksController#facebook
找不到 true 的有效映射
提取的源代码(第 5 行附近):
class CallbacksController < Devise::OmniauthCallbacksController
# Define each provider for omniauth here (def twitter...)
def facebook
@user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect @user
end
end
user.rb 模型看起来像这样:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook]
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first
unless user
user = where(email: auth.info.email).first_or_initialize
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.nickname = auth.info.nickname
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.location = auth.info.location
user.description = auth.info.description
user.image = auth.info.image
user.phone = auth.info.phone
user.urls = auth.info.urls
user.password = Devise.friendly_token[0,20]
user.save!
end
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
resources :auctions do
resources :comments
end
root 'welcome#index'
get '/', :to => 'welcome#index'
end
您的 User
class 中的 self.from_omniauth
方法是 returning true
,而不是 User
模型。这是因为return Ruby is the result of the last line evaluated, and in this case user.save!
is the last line that runs. The "Could not find a valid mapping for true" error is a result of passing true
into sign_in_and_redirect
; you can see in the Devise source that the first argument is passed into Devise::Mapping.find_scope!
中方法的值。
解决方案很简单 - 确保您 return 在 from_omniauth
:
中构建您的 user
模型
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first
unless user
user = where(email: auth.info.email).first_or_initialize
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.nickname = auth.info.nickname
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.location = auth.info.location
user.description = auth.info.description
user.image = auth.info.image
user.phone = auth.info.phone
user.urls = auth.info.urls
user.password = Devise.friendly_token[0,20]
user.save!
end
user # Make sure we return the user we constructed.
end
我正在使用 omniauth facebook gem 进行设计以构建注册系统。用户可以使用电子邮件注册或使用他们的 Facebook 帐户连接。 如果一个邮箱注册的用户使用facebook账号登录,我会检查邮箱地址是否已经注册并连接这两个账号,然后让用户登录。
整个场景已经可以运行了。使用 facebook 的新 omniauth 数据更新用户条目。我得到这个错误,当 facebooks 发送回调时(来自 facebook 的数据已成功保存到 db):
RuntimeError in CallbacksController#facebook
找不到 true 的有效映射
提取的源代码(第 5 行附近):
class CallbacksController < Devise::OmniauthCallbacksController
# Define each provider for omniauth here (def twitter...)
def facebook
@user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect @user
end
end
user.rb 模型看起来像这样:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook]
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first
unless user
user = where(email: auth.info.email).first_or_initialize
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.nickname = auth.info.nickname
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.location = auth.info.location
user.description = auth.info.description
user.image = auth.info.image
user.phone = auth.info.phone
user.urls = auth.info.urls
user.password = Devise.friendly_token[0,20]
user.save!
end
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
resources :auctions do
resources :comments
end
root 'welcome#index'
get '/', :to => 'welcome#index'
end
您的 User
class 中的 self.from_omniauth
方法是 returning true
,而不是 User
模型。这是因为return Ruby is the result of the last line evaluated, and in this case user.save!
is the last line that runs. The "Could not find a valid mapping for true" error is a result of passing true
into sign_in_and_redirect
; you can see in the Devise source that the first argument is passed into Devise::Mapping.find_scope!
中方法的值。
解决方案很简单 - 确保您 return 在 from_omniauth
:
user
模型
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first
unless user
user = where(email: auth.info.email).first_or_initialize
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.nickname = auth.info.nickname
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.location = auth.info.location
user.description = auth.info.description
user.image = auth.info.image
user.phone = auth.info.phone
user.urls = auth.info.urls
user.password = Devise.friendly_token[0,20]
user.save!
end
user # Make sure we return the user we constructed.
end