I am getting undefined method `[]' for nil:NilClass
NoMethodError in Users::OmniauthCallbacksController#facebook
undefined method `[]' for nil:NilClass
Rails.root: /home/krishna/picer
Application Trace | Framework Trace | Full Trace
app/models/user.rb:13:in `find_for_facebook_oauth'
app/controllers/users/omniauth_callbacks_controller.rb:4:in `facebook'
This is my user.rb code
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable:omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
data = access_token['extra']['user_hash']
if user = User.find_by_email(data["email"])
user
else # Create a user with a stub password.
User.create(:email => data["email"], :password => Devise.friendly_token[0,20])
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"] ["extra"]["user_hash"]
user.email = data["email"]
end
end
end
end
And omniauth callbacks controller code
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.facebook_data"] = env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def passthru
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
end
I am getting error line four user.rb I used a example for this https://github.com/ryanatwork/devise-omniauth
You should get the user email with access_token['info']['email'] instead of access_token['extra']['user_hash']['email'].
I don't think the data in access_token['extra'] follows a convention like the rest, so you should be extra careful and test if the property you're trying to access exists. It's not that important if you only have one provider, but it is if you have several of them.
Related
I have a rails app and I want to make a Github connect. I have followed the devise tutorial about Facebook and adapted it for Github.
I have this error on the callback, when accessing /users/auth/github/callback?code=xxxxxxx
ActionController::RoutingError (uninitialized constant Users):
I know that other posts are related to this issue but their answer do not fix my problem.
routes.rb
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def github
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Github") if is_navigational_format?
else
session["devise.github_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
models/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 => [:github]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.github_data"] && session["devise.github_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
end
NoMethodError (undefined method `persisted?' for nil:NilClass):
This is the error i get when trying to use omniauth with Devise...
I am able to signup for the site with facebook...
but once i log out
and try to log back in i get the
NoMethodError (undefined method `persisted?' for nil:NilClass):
class Models::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#model = Model.find_for_facebook_oauth(request.env["omniauth.auth"], current_model)
if #model.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #model, :event => :authentication
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_model_registration_url
end
end
def passthru
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
# Or alternatively,
# raise ActionController::RoutingError.new('Not Found')
end
end
model.rb
class Model < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :provider, :uid
# attr_accessible :title, :body
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
model = Model.where(:provider => auth.provider, :uid => auth.uid).first
unless model
model = Model.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
end
def self.new_with_session(params, session)
super.tap do |model|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
model.email = data["email"] if model.email.blank?
end
end
end
end
Your find_for_facebook_oauth method is implicitly returning nil in cases where a model is found. You should explicitly return the model if it is found instead.
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
model = Model.where(:provider => auth.provider, :uid => auth.uid).first
return model if model
model = Model.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
model = Model.where(:provider => auth.provider, :uid => auth.uid).first
unless model
model = Model.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
model #Add this here
end
I followed this tutorial precisely but I am getting this error:
NoMethodError in SessionsController#create
undefined method `slice' for nil:NilClass
Rails.root: /Users/raybesiga/Documents/Sites/foodie
Application Trace | Framework Trace | Full Trace
app/models/user.rb:29:in from_omniauth'
app/controllers/sessions_controller.rb:3:increate'
However my user.rb file is as below:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :provider, :uid
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive => false
# attr_accessible :title, :body
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
end
My sessions_controller.rb file is as follows:
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["ominauth.auth"])
# session[:user_id] = user.user_id
session[:user_id] = user.id
redirect_to root_url
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
Any idea why I get this error?
You spelled env['omniauth.auth'] wrong in your sessions controller. You put env['ominauth.auth']
Hi I am using devise and omniauth to autenticate facebook login, but I get the following error:
Can't mass-assign protected attributes: token
app/models/user.rb:20:in `apply_omniauth'
app/controllers/authentications_controller.rb:19:in `create'
this the user model:
class User < ActiveRecord::Base
# The relationship between the User and Authentication model
has_many :authentications, :dependent => :delete_all
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
# attr_accessible :title, :body
def apply_omniauth(auth)
# In previous omniauth, 'user_info' was used in place of 'raw_info'
self.email = auth['extra']['raw_info']['email']
authentications.build(:provider => auth['provider'], :uid => auth['uid'], :token => auth['credentials']['token'])
end
end
This is my authentication controller:
class AuthenticationsController < ApplicationController
def index
#authentications = current_user.authentications if current_user
end
def create
auth = request.env["omniauth.auth"]
# Try to find authentication first
authentication = Authentication.find_by_provider_and_uid(auth['provider'], auth['uid'])
if authentication
# Authentication found, sign the user in.
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
else
# Authentication not found, thus a new user.
user = User.new
user.apply_omniauth(auth)
if user.save(:validate => false)
flash[:notice] = "Account created and signed in successfully."
sign_in_and_redirect(:user, user)
else
flash[:error] = "Error while creating a user account. Please try again."
redirect_to root_url
end
end
end
def destroy
#authentication = Authentication.find(params[:id])
#authentication.destroy
redirect_to authentications_url, :notice => "Successfully destroyed authentication."
end
end
Could somebody explain why I get this error, and how I fix it?
Adding :token to the attr_accessible line in the authentication model should do the trick.
My app is set up so that if a user signs in with Oauth or Openid, they don't have to confirm their email address. However, Devise is still sending email confirmations. When I call User.skip_confirmation! I get an undefined method error. My model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable,
:trackable, :validatable, :confirmable, :lockable, :token_authenticatable, :omniauthable
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
validates_presence_of :username
validates_uniqueness_of :username, :case_sensitive => false
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
data = access_token.extra.raw_info
if user = User.where(:email => data.email).first
user
else
#User.skip_confirmation!
User.create!(:username => data.name, :email => data.email, :password => Devise.friendly_token[0,20])
end
end
def skip_confirmation!
self.confirmed_at = Time.now
end
end
My Controller:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
#user.skip_confirmation!
if #user.persisted?
sign_in #user
#fname = #user.username
redirect_to root_path, :flash => { :success => "Welcome #{#fname}!" }
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
thanks for any help.
You need to skip confirmation before you create the User objects and its persisted to the database. So the user creation part of your method would look like
user = User.new(:username => data.name, :email => data.email, :password => Devise.friendly_token[0,20])
user.skip_confirmation!
user.save
If you're updating a user record, make sure to use skip_reconfirmation! (mind the re)