I am using rails cast omniauth and i get this error - ruby-on-rails

I am using Mongodb as database in rails and i got error when using /auth/linkedin/callback
NoMethodError in AuthenticationsController#create undefined method []' for nil:NilClass Rails.root: /home/prem/Music/heronhrm Application Trace | Framework Trace | Full Trace app/models/user.rb:57:in apply_omniauth' app/controllers/authentications_controller.rb:19:in `create'
Also when i remove self.email = omniauth['user_info']['email'] if email.blank? from usermodel then the validation errors arises in
users/sign_up Email can't be blank
I want to implement for twitter,linkdin and facebook.
my authentication.rb
class Authentication
include Mongoid::Document
belongs_to :user
field :user_id, :type => String
field :provider, :type => String
field :uid, :type => String
def self.find_by_provider_and_uid(provider, uid)
where(provider: provider, uid: uid).first
end
end
my user model is like this
def apply_omniauth(omniauth)
self.email = omniauth['user_info']['email'] if email.blank?
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
end
def password_required?
(authentications.empty? || !password.blank?) && super
end
My authentications controller is like this
class AuthenticationsController < ApplicationController
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication = current_user.authentications.find(params[:id])
#authentication.destroy
flash[:notice] = "Successfully destroyed authentication."
redirect_to authentications_url
end
protected
# This is necessary since Rails 3.0.4
# See https://github.com/intridea/omniauth/issues/185
# and http://www.arailsdemo.com/posts/44
def handle_unverified_request
true
end
end
My registration controller is like this
class RegistrationsController < Devise::RegistrationsController
def create
super
session[:omniauth] = nil unless #user.new_record?
end
private
def build_resource(*args)
super
if session[:omniauth]
#user.apply_omniauth(session[:omniauth])
#user.valid?
end
end
end

Inside your app/models/authentication.rb add this
def self.find_by_provider_and_uid(provider, uid)
where(provider: provider, uid: uid).first
end

Did you add this in your model? If not added then add this and then try
key :provider, String
key :uid, String

Related

current_user helper method returning error in mongoid backed authentication

I am using omniauth-twitter gem for authentication. And my rails app is backed by Mongodb.
When clicked on Login it opened the twitter profile. I entered the credentials and got redirected back to the app with an error saying
unknown operator: $oid (2)
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
helper_method :current_user
It is pointing error at the #current_user line. But when I checked the database for the user created by doing User.last, I can see a user object.
User.rb file
class User
include Mongoid::Document
field :provider, type: String
field :uid, type: String
field :name, type: String
field :location, type: String
field :image_url, type: String
field :url, type: String
index({ provider: 1, uid: 1 }, { unique: true})
class << self
def from_omniauth(auth_hash)
user = find_or_create_by(uid: auth_hash['uid'], provider: auth_hash['provider'])
user.name = auth_hash['info']['name']
user.location = auth_hash['info']['location']
user.image_url = auth_hash['info']['image']
user.url = auth_hash['info']['urls']['Twitter']
user.save!
user
end
end
end
Then I created a sessions controller and looks as follows.
class SessionsController < ApplicationController
def create
begin
#user = User.from_omniauth(request.env['omniauth.auth'])
session[:user_id] = #user.id
flash[:success] = "Welcome, #{#user.name}!"
rescue
flash[:warning] = "There was an error while trying to authenticate you..."
end
redirect_to root_path
end
def destroy
if current_user
session.delete(:user_id)
flash[:success] = 'See you!'
end
redirect_to root_path
end
end
Can someone please help me fix this ?

Rails 4: User Authentication - NoMethodError

I've setup a moreless simple social user authentification on top of devise using Google, Linkedin, Dropbox and Github.The Dropbox authentication does not work, instead it gives that error on the callback URL(http://localhost:3000/users/auth/dropbox/callback):
NoMethodError in Users::OmniauthCallbacksController#dropbox
undefined method `first' for nil:NilClass
Issue: User Model (line 8)
My Code:
Callbacks Controller:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(env['omniauth.auth'], current_user)
if user.persisted?
sign_in user
flash[:notice] = t('devise.omniauth_callbacks.success', :kind => User::SOCIALS[params[:action].to_sym])
if user.sign_in_count == 1
redirect_to edit_user_registration_path
else
redirect_to root_path
end
else
session['devise.user_attributes'] = user.attributes
redirect_to new_user_registration_url
end
end
User::SOCIALS.each do |k, _|
alias_method k, :all
end
end
User Model:
# omniauth Gem
def self.from_omniauth(auth, current_user)
authorization = Authorization.where(:provider => auth.provider, :uid => auth.uid.to_s,
:token => auth.credentials.token,
:secret => auth.credentials.secret).first_or_initialize
authorization.profile_page = auth.info.urls.first.last unless authorization.persisted?
if authorization.user.blank?
user = current_user.nil? ? User.where('email = ?', auth['info']['email']).first : current_user
if user.blank?
user = User.new
user.skip_confirmation!
user.password = Devise.friendly_token[0, 20]
user.fetch_details(auth)
user.save
end
authorization.user = user
authorization.save
end
authorization.user
end
def fetch_details(auth)
self.email = auth.info.email
self.username = auth.info.name
self.avatar = URI.parse(auth.info.image)
end
I appreciate each help! Thanks in advance.
To answer your question directly:
The undefined method "first" for nil::NilClass is happening because you are attempting to call the method first on an empty, or nil object.
It's probably in your user model where you are attempting to find a User from a current_user.
if authorization.user.blank?
user = current_user.nil? ? User.where('email = ?', auth['info']['email']).first : current_user
#This will cause the error that you are describing if both the current_user is nil and there is no User whose email is auth['info']['email']
Now, There's a few things wrong with this. If they are attempting to log in to your application, then current_user at this stage should be unset.
You could try changing this to
user = User.where(email: auth['info']['email']).first_or_create
Which will create a new instance of User, if one does not exist with the email provided in the Authorization.
Then you can continue with
user.persisted?
which returns true for an existing user, and false for a new instance of User

How to update an existing Users record

I'm working on a application which contains the soundcloud api.
i have the user login and model and i would like to append the soundcloud_id and token to the existing user but i cannot somehow update the users record.
what do i do wrong?
soundcloud controller
class SoundcloudController < ApplicationController
def connect
# create client object with app credentials
client = Soundcloud.new(:client_id => ENV["SOUNDCLOUD_CLIENT_ID"],
:client_secret => ENV["SOUNDCLOUD_CLIENT_SECRET"],
:redirect_uri => "http://localhost:3000/soundcloud/oauth-callback",
:response_type => 'code')
# redirect user to authorize URL
redirect_to client.authorize_url(:grant_type => 'authorization_code', :scope => 'non-expiring', :display => 'popup')
end
def connected
# create client object with app credentials
client = Soundcloud.new(:client_id => ENV["SOUNDCLOUD_CLIENT_ID"],
:client_secret => ENV["SOUNDCLOUD_CLIENT_SECRET"],
:redirect_uri => "http://localhost:3000/soundcloud/oauth-callback")
# exchange authorization code for access token
access_token = client.exchange_token(:code => params[:code])
client = Soundcloud.new(:access_token => access_token["access_token"])
# make an authenticated call
soundcloud_user = client.get('/me')
unless User.where(:soundcloud_user_id => soundcloud_user["id"]).present?
#User.create_from_soundcloud(soundcloud_user, access_token)
UsersController.add_soundcloud_account(soundcloud_user, access_token)
end
sign_in_user = User.where(:soundcloud_user_id => soundcloud_user["id"])
#create user sessions
#session[:user_id] = sign_in_user.first.id
redirect_to root_url, notice: "Signed in!"
end
def destroy
end
end
user controller
class UsersController < ApplicationController
def new
#user = User.new
end
#create a user and redirect to home
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to '/'
else
redirect_to '/signup'
end
end
def self.add_soundcloud_account(soundcloud_user, access_token)
#current_user ||= User.find(session[:user_id])
#current_user.soundcloud_user_id = soundcloud_user["id"]
#current_user.soundcloud_access_token = access_token["access_token"]
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password)
end
end
You need to call save on the #current_user and pass in the session information to the method:
def self.add_soundcloud_account(user_id, soundcloud_user, access_token)
#current_user ||= User.find(user_id)
#current_user.soundcloud_user_id = soundcloud_user["id"]
#current_user.soundcloud_access_token = access_token["access_token"]
#current_user.save
end
It is called like this:
UsersController.add_soundcloud_account(session[:user_id], soundcloud_user, access_token)
However I am not sure the add_soundcloud_account method belongs in a controller. I would prefer to see it in a Service or maybe just in the User model.

action mailer rails ArgumentError in Password_resets#create

I set up a basic sign in, login, sign out format for a rails app and I was going to give it a function so that if a person forgot their password they could get a email back. when I went click on submit password reset I got
Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
Extracted source (around line #3):
1: To reset your password click the URL below.
2:
3: <%= edit_password_reset_url(#user.password_reset_token) %>
4:
5: If you did not request your password to be reset please ignore this email and your password will stay as it is.
Rails.root: /Users/cheatermoves/nightclass/mainproject/project
Application Trace | Framework Trace | Full Trace
app/views/user_mailer/password_reset.text.erb:3:in `_app_views_user_mailer_password_reset_text_erb__3613112772785486465_70118994937040'
app/mailers/user_mailer.rb:6:in `password_reset'
app/models/user.rb:17:in `send_password_reset'
app/controllers/password_resets_controller.rb:7:in `create'
just completed rails cast 250 and was doing 274. Everything was fine until I got this problem.
here is my controllers. Password resets:
class PasswordResetsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to root_url, :notice => "Email sent with password reset instructions."
end
end
sessions:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
cookies.delete(:auth_token)
redirect_to root_url, :notice => "Logged out!"
end
end
users:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
end
and application:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find_by_auth_token( cookies[:auth_token]) if cookies[:auth_token]
end
helper_method :current_user
end
in environments/development.rb I have
config.action_mailer.default_url_options = { :host => "localhost:3000" }
here is my user model
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
validates_presence_of :password, :on => :create
before_create { generate_token(:auth_token) }
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
end
user_mailer.rb file
class UserMailer < ActionMailer::Base
default from: "from#example.com"
def password_reset(user)
#user = user
mail :to => user.email, :subject => "Password Reset"
end
end
anyone know what the problem is and how to fix it? I'm using rails 3.2.14 if anyone is wondering. Thanks!
Didn't read the part where you said that you already set your
config.default_url_options[:host] = "localhost:3000"
my bad, sorry

How to bypass Twitter omniauth "email can't be blank" error?

I am having a little trouble with Twitter authentication. I keep getting the email can't be blank, and redirect to sign up, but after inserting email and clicking sign up, I still get the same error. I tried making it unneeded, but I get the error saying that someone with "" email exists already.
Thanks.
Devise Routes.rb
def has_role?(role)
return true;
end
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.username = auth.info.nickname
end
end
def self.new_with_session(params, session)
if session["devise.user_attributes"]
new(session["devise.user_attributes"]) do |user|
user.attributes = params
user.valid?
end
else
super
end
end
def password_required?
super && provider.blank?
end
def update_with_password(params, *options)
if encrypted_password.blank?
update_attributes(params, *options)
else
super
end
end
end
Call Back Controller
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Signed in!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
alias_method :twitter, :all
end
You can define username to be your "authentication key" instead of email by
uncommenting this line
config.authentication_keys = [ :email ]
in config/initializers/devise.rb
and changing it to
config.authentication_keys = [ :username ]
i also had the same problem.
this error arises due the fact that in devise User model Email field is set to NotNull.
Solutions:-
1.Set email field in devise to allow null values.
2.so i had saved the email from twitter in my devise email field this is the code for twitter
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
temp = Tempfile.new([auth["uid"], ".jpg"])
temp.binmode
temp.write(open(auth["info"]["image"]).read)
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],
image:temp
)
user.build_profile(name:user.name,image:temp)
user.profile.save
end
user
end

Resources