I am setting up devise with omniauth facebook gem to build a signup system. Users can either register with email or connect with their facebook account. If an email registered user signs in with the facebook account, I check if the email address is already registered and connect these two accounts, and then log the user in.
This whole scenario works already. The user entry is updated with the new omniauth data of facebook. I get this error, when facebooks sends the callback (data from facebook is saved to db successfully):
RuntimeError in CallbacksController#facebook
Could not find a valid mapping for true
Extracted source (around line #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 modell looks like this:
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
Your self.from_omniauth
method in your User
class is returning true
, instead of a User
model. It's because the return value of a method in 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!
.
The solution's simple - make sure that you're returning your user
model in from_omniauth
:
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