Facebook redirects to sign up page after authenticating user Rails - facebook

I am intergrating Facebook login using device, and after allowing Facebook to get your info it redirects you to the sign up page. Here's my code:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :description, :photo ])
devise_parameter_sanitizer.permit(:account_update, keys: [:username, :first_name, :last_name, :description, :photo ])
end
end
Callback controller
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#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 => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
And my user model is
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
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]
user.first_name = auth.info.name # assuming the user model has a name
user.image = auth.info.image # assuming the user model has an image
end
end
I'd really appreciate an extra eye on what I'm doing wrong, or where I am missing something. Thanks!

You need to add this column for provider and uid to your users table, i think rails can't match your user :
rails g migration add_provider_and_uid_to_users provider:string uid: string
And try to write me the rails server response it Can help to figure out the bug source

Related

Ruby on Rails Tutorial NoMethodError in Users#index

I'm reading Michael Hartl's great "The Ruby on Rails Tutorial". And I faced a problem that wasn't described in the book.
I push a submit button on a Sign up page with blank fields, then, as it expected, the mistakes messages like these appears:
Name can't be blank
Email can't be blank
Email is invalid
Password can't be blank
But the URL changes from http://[::1]:3000/signup to http://[::1]:3000/users
Then I push the Chrome's refresh button and get redirecting to exactly http://[::1]:3000/users URL.
I understand that the pushing the submit button directs to .../users URL. How to change this route to the right one (still http://[::1]:3000/signup)?
Here's my users_controller.rb file
class UsersController < ApplicationController
before_action :logged_in_user, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
#users = User.where(activated: true).paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
redirect_to root_url and return unless #user.activated?
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'users/new', status: :unprocessable_entity
end
end
def edit
#user = User.find(params[:id])
end
end
Here's my routes.rb file
Rails.application.routes.draw do
get 'password_resets/new'
get 'password_resets/edit'
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
default_url_options :host => "example.com"
resources :users
end
Thanks in advance!

Devise facebook login. #user not persisting, getting redirected to sign up page

I followed all the instructions in Omniauth's walkthrough.
Note that my User model does not have name or image properties.
I followed the instructions in the Rails tutorial. However, I did have to change 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)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.name = auth.info.name # assuming the user model has a name
user.image = auth.info.image # assuming the user model has an image
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
end
to 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)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
# user.name = auth.info.name # assuming the user model has a name
# user.image = auth.info.image # assuming the user model has an image
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
end
an error was being thrown because User doesn't have name or image properties.
That led to a new error:
The #user created in the Omniauth_callbacks_controller is not persisting, so instead of getting signed-in, I'm just getting redirected back to the user sign-up page.
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.from_omniauth(request.env["omniauth.auth"])
puts "BEFORE IF STATEMENT"
puts #user.inspect
if #user.persisted?
puts "INSIDE IF STATEMENT"
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
puts "AFTER ELSE STATEMENT"
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
Server read out, which includes the puts statement and the #user object. You'll see that most of its fields are nil:
Started GET "/users/auth/facebook" for ::1 at 2015-09-01 20:41:01 +0100
I, [2015-09-01T20:41:01.891561 #7662] INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/users/auth/facebook" for ::1 at 2015-09-01 20:41:01 +0100
I, [2015-09-01T20:41:01.978637 #7662] INFO -- omniauth: (facebook) Request phase initiated.
Started GET "/users/auth/facebook/callback?code=AQBcPU1SSS5908ZaCIgZjKnffSjG0PZTNcoyeSjiTbZDbVZvOKIz_YDoZzijNvfuc5QdIHczQPVAFqv3TMxDPZ_lGdUC3sg6d9iScaBgwVqU6uuoGppV7fAO-Q2ALN48is9-Exkr1o0JF2Yry9nebSxcSEDpBz39jDU0EMxOWCShGwG0CCaKLavOo0GzXzmZr1mpYaUZoBgxHSUdr3rRfhoqYMZOrYAYQeR8DMcAw7WR-C4PNKN9NyMwhzWDFv7mtoneP6dWAd22SNOLmQC64ahgJTFsN76brLl1Xl6HYR0wqjd4LBJeeV4uAumdVWkiIgo&state=0c40e8bcabffe59ec093223f78250db73c9a3d9b7717be97" for ::1 at 2015-09-01 20:41:02 +0100
I, [2015-09-01T20:41:02.098574 #7662] INFO -- omniauth: (facebook) Callback phase initiated.
Processing by Users::OmniauthCallbacksController#facebook as HTML
Parameters: {"code"=>"AQBcPU1SSS5908ZaCIgZjKnffSjG0PZTNcoyeSjiTbZDbVZvOKIz_YDoZzijNvfuc5QdIHczQPVAFqv3TMxDPZ_lGdUC3sg6d9iScaBgwVqU6uuoGppV7fAO-Q2ALN48is9-Exkr1o0JF2Yry9nebSxcSEDpBz39jDU0EMxOWCShGwG0CCaKLavOo0GzXzmZr1mpYaUZoBgxHSUdr3rRfhoqYMZOrYAYQeR8DMcAw7WR-C4PNKN9NyMwhzWDFv7mtoneP6dWAd22SNOLmQC64ahgJTFsN76brLl1Xl6HYR0wqjd4LBJeeV4uAumdVWkiIgo", "state"=>"0c40e8bcabffe59ec093223f78250db73c9a3d9b7717be97"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."provider" = $1 AND "users"."uid" = $2 ORDER BY "users"."id" ASC LIMIT 1 [["provider", "facebook"], ["uid", "10153518057141280"]]
(0.2ms) BEGIN
(0.2ms) ROLLBACK
BEFORE IF STATEMENT
#<User id: nil, email: nil, encrypted_password: "$2a$10$6Ls8Eng6pNFz11sV/AmOuuUdq8JRas33H8UnWAX0YyA...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil, provider: "facebook", uid: "10153518057141280">
AFTER ELSE STATEMENT
Redirected to http://localhost:3000/users/sign_up
Completed 302 Found in 93ms (ActiveRecord: 1.1ms)
Started GET "/users/sign_up" for ::1 at 2015-09-01 20:41:02 +0100
Processing by Devise::RegistrationsController#new as HTML
Rendered /Users/makerslaptop91/.rvm/gems/ruby-2.2.0/gems/devise-3.5.1/app/views/devise/shared/_links.html.erb (1.0ms)
Rendered /Users/makerslaptop91/.rvm/gems/ruby-2.2.0/gems/devise-3.5.1/app/views/devise/registrations/new.html.erb within layouts/application (6.9ms)
Completed 200 OK in 55ms (Views: 54.3ms | ActiveRecord: 0.0ms)
Notice the puts inside the 'if' statement was never printed.
routes.rb:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
resources :restaurants do
resources :reviews
end
root to: "restaurants#index"
I'm stumped.
If you remove the :validatable option then it will work.

redircting error in ruby on rails

I'm new to ruby on rails. I tried to redirect to outlet_controller#map, but the below code redirect me to #show. what i am doing wrong. help me to sort out.
my route is
namespace :api do
get 'outlet/map' => 'outlets#map'
end
my controller is
class Api::OutletsController < ApplicationController
http_basic_authenticate_with :name => "admin", :password => "password"
skip_before_filter :authenticate_user!
before_filter :fetch_outlets, :except => [:index, :create]
def fetch_outlets
#outlet = Outlet.find_by_id(params[:id])
end
def index
respond_to do |format|
#outlets = Outlet.select(:name, :description, :latitude, :longitude, :contact, :image_url, :emailid).all
##outlets = Outlet.all
format.json { render json: #outlets}
end
end
def auto_complete
params.permit!
query = params[:query]
#outlet = Outlet.select(:name).where("name like ?","#{query}%")
if #outlet.present?
respond_to do |format|
format.json { render json: #outlet }
end
elsif
render :json=> {:status=>'error', :message=>'Data not found'}
end
end
def search
params.permit!
query = params[:query]
puts YAML::dump(query)
#outlet = Outlet.select(:name, :description, :latitude, :longitude, :contact, :image_url, :emailid).where("name like ?","%#{query}%")
if #outlet.present?
respond_to do |format|
format.json { render json: #outlet }
end
elsif
render :json=> {:status=>'error', :message=>'Data not found'}
end
end
def show
respond_to do |format|
format.json { render json: #outlet }
end
end
def create
#outlet = Outlet.new(params[:outlets])
respond_to do |format|
if #outlet
format.json { render json: #outlet, status: :created }
else
format.json { render json: #outlet.errors, status: :unprocessable_entity }
end
end
end
def update
if #outlet.update_attributes(outlet_params)
render :json=> {:status=>'success', :message=>'Successfully Updated'}
else
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
def map
super
end
def destroy
if #outlet.destroy
render :json=> {:status=>'success', :message=>'Successfully Removed'}
else
format.json { render json: #outlet.errors, status: :unprocessable_entity }
end
end
private
def outlet_params
params.require(:outlets).permit(:name, :brand_id, :latitude, :langitude, :location, :description, :image_url, :contact, :emailid)
end
end
my development log for
/api/outlets/map
is
Started GET "/api/outlets/map" for 127.0.0.1 at 2015-06-01 17:18:59 +0530
Processing by Api::OutletsController#show as JSON
Parameters: {"id"=>"map"}
[1m[35mOutlet Load (0.2ms)[0m SELECT `outlets`.* FROM `outlets` WHERE `outlets`.`id` = 0 LIMIT 1
Completed 200 OK in 15ms (Views: 0.3ms | ActiveRecord: 0.2ms)
why i'm redirect to outlets_controller#show? could anyone help to sort out this problem...
The problem could be the order of route definitions in your routes.rb.
This order of routes would trigger the problematic behaviour, because Rails will use the first route that matches the request:
YourApp.routes.draw do
namespace :api do
resources :outlets # defines the show route
get 'outlet/map' => 'outlets#map'
end
end
To fix this, change the order of your routes:
YourApp.routes.draw do
namespace :api do
get 'outlet/map' => 'outlets#map'
resources :outlets # defines the show route
end
end
Now the route outlet/map matches before outlet/:id does.
You can also try this route definition if it is applicable:
YourApp.routes.draw do
namespace :api do
resources :outlets do
get 'map', on: :collection
end
end
end

Rails 4, devise, omniauth, facebook: problems when regular sign up involves nested forms

I am trying to set up facebook login integration with omniauth and devise.
Note that I have a MEMBER model which contains the devise info and a USER model that contains the member profile info (to keep them separate)
On the sign up page, the user has a nested form in the member sign up form and receives all the user data at that time. Once the member is saved, the email value for the saved member is also entered into the user table like so
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :omniauthable
after_save :update_user
def update_user
user.email = self.email
user.save
end
I have the standard model method for the facebook data processing.....
def self.process_omniauth(auth)
where(provider: auth.provider, uid: auth.uid, email: auth.info.email).first_or_create do |member|
member.provider = auth.provider
member.uid = auth.uid
member.email = auth.info.email
end
end
But of course, in this case, there is no nested form so the 'user' is not instantiated and it throws an error when the update_user method is called on saving the member.
How can I modify this method above to instantiate a new user, when signing up via the facebook pathway?
EDIT: This works.....
def update_user
if User.find_by_member_id(self.id).present?
user.email = self.email
user.save
else
User.create(:email => self.email, :member_id => self.id)
end
end
BUT THIS RESULTS IN A CONSTRAINT ERROR - on email - it already exists in the database. From the logs, the else statement here appears to be attempting to create the user twice.
def update_user
if User.find_by_member_id(self.id).present?
user.email = self.email
user.save
else
User.create(:email => self.email)
end
end
Can anyone explain this? I am suprised I had to pass the foreign key to the user in the else block.
I'm not sure what fields are being stored in the User Model but what you should be doing here that in case of Facebook Callback you should create the User if the Member don't have an user associated with it. i.e your update_user should be something like this:
def update_user
if user.present?
user.email = self.email
user.save
else
User.create(:email => self.email, :member_id => self.id)
/*note that a lot of other information is returned in
facebook callback like First Name, Last Name, Image and
lot more, which i guess you should also start saving to
User Model */
end
end
**** EDIT ******** . You should also check if there is user with the same email and associate that with the member.
def update_user
if user.present?
user.email = self.email
user.save
else
user = User.find_by_email(self.email)
if user
user.update_attribute(:member_id, self.id)
else
User.create(:email => self.email, :member_id => self.id)
end
end

Calling Document.find with nil is invalid MongoId in Rails 4

There are three models in my app: User, Subject and Note.
I've already embedded Note model into Subject model and it works. Now when I try to embed Subject into User always get Mongoid::Errors::InvalidFind coming from this line of code:
In the method one should define to use in before_action at the beginning of the controller
#user = User.find(params[:user_id])
subjects_controller
class SubjectsController < ApplicationController
#before_filter :authenticate_user!, only: [:index]
before_action :set_subject, only: [:show, :edit, :update, :destroy]
before_action :load_user
def index
#subjects = #user.subjects
end
def new
#subject = #user.subjects.build
end
def show
end
def create
#subject = #user.subjects.create(subject_params)
respond_to do |format|
if #subject.save
format.html {redirect_to subject_path(#subject)}
else
format.html {render 'new'}
end
end
end
def update
if #subject.update(subject_params)
redirect_to #subject
else
render 'edit'
end
end
def delete
end
private
def subject_params
params.require(:subject).permit(:name)
end
def set_subject
#subject = #user.subject.find(params[:id])
end
def load_user
#user = User.find(params[:user_id])
end
end
Routes
resources :users do
resources :subjects do
resources :notes
end
end
Right now I'm pretty stuck here because haven't found a way to work this around, hope someone around can give a hand.
Take into account this RoR best practice "Resources should never be nested more than 1 level deep." http://guides.rubyonrails.org/routing.html#nested-resources
A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason).
http://weblog.jamisbuck.org/2007/2/5/nesting-resources