How to save the request.referrer for facebook omniauth in Rails 4
Asked Answered
T

1

1

I have two facebook buttons in my application. One on users/sign_up and other on /visitors/owner-faq. I want to save the request.referrer in order to know from which page the user has signed up. I had implemented the same for external signup(which uses a form) and it worked. Now I'm unable to implement the same for facebook omniauth.

Code:

#user.rb

def self.from_omniauth(auth) 
    email         = auth.info.email 
    user          = User.find_by_email(email)   # first tries to find an existing user who signed up normal way with the same email to sign them in 
    if user && user.confirmed?                
      user.provider = auth.provider
      user.uid      = auth.uid
      return user
    end

    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|  # then tries to find the user who authenticated through FB, and if
      user.email            = auth.info.email                                # not present, creates that user
      user.password         = Devise.friendly_token[0,20]
      user.first_name       = auth.info.first_name
      user.last_name        = auth.info.last_name
      user.social_photo_url = auth.info.image
      user.skip_confirmation!   
    end
  end

#users/omniauth_callbacks_controller

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"]
      Rails.logger.info(@user.errors.inspect) 
      redirect_to new_user_registration_url
    end
  end

#application_controller.rb

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  before_filter :store_referrer_url, :only => [:new]

  private

  def store_referrer_url
    session[:referrer] = URI(request.referer).path
  end
end

Attempt #1:

I managed to save the request.referrer like this in users/omniauth_callbacks_controller

def facebook
    @user = User.from_omniauth(request.env["omniauth.auth"])
    @user.referrer_url = session[:referrer] #here
    @user.save!

    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"]
      Rails.logger.info(@user.errors.inspect) 
      redirect_to new_user_registration_url
    end
  end

But the problem here is the value of referrer_url is overwritten when the existing user logs in from another page. I don't want to get the referrer_url to be overwritten.

Attempt #2:

I tried to save the request.referrer in the from_omniauth(auth) method User model like this

def self.from_omniauth(auth) 
    email         = auth.info.email 
    user          = User.find_by_email(email)   # first tries to find an existing user who signed up normal way with the same email to sign them in 
    if user && user.confirmed?                
      user.provider = auth.provider
      user.uid      = auth.uid
      return user
    end

    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|  # then tries to find the user who authenticated through FB, and if
      user.email            = auth.info.email                                # not present, creates that user
      user.password         = Devise.friendly_token[0,20]
      user.first_name       = auth.info.first_name
      user.last_name        = auth.info.last_name
      user.social_photo_url = auth.info.image
      user.referrer_url     = session[:referrer]
      user.skip_confirmation!   
    end
  end

But it gave me this error

undefined local variable or method `session' for #<Class:0x0000000e1c46f8>

Any suggestions would be greatly helpful.

Tripp answered 8/6, 2015 at 7:18 Comment(1)
remove :only => [:new] in the application controller. you normally only want to do that in other controllers. that's the most probable reason why you're not getting any referrer with omniauth.Franky
A
1

If you want the referrer_url property to stay the same after it's first set, you should use the OR Equal operator, that will only set the value if it's currently nil or false:

@user.referrer_url ||= session[:referrer]

If I understand correctly, your facebook callback is called both on sign up and login, and of course the value would be overwritten. OR Equals will prevent the value from being overwritten once it's set.

Regarding Attempt #2, the session hash is only available in the controller and the view, so you can't use it in the model.

Another possibility:

You are setting session[:referrer] in your store_referrer_url method which is called in a before_filter callback on the new method.

Most likely your login is also made with a new method (for example, with Devise it would be in SessionsController), so the callback is called again and the value is overwritten (all Devise controllers inherit from your ApplicationController). In this case, you could take out the before_filter callback out of the ApplicationController to the controller where you are handling signing up (would be RegistrationsController with Devise).

Alfeus answered 8/6, 2015 at 7:29 Comment(2)
It still overwrites the referrer_url after changing to session[:referrer] ||= URI(request.referer).pathTripp
Oops, my mistake, please see the edit. Of course session[:referrer] would be cleared out. You can also put the @user.referrer_url = session[:referrer] line inside the if @user.persisted? and save the object again, so it won't be set on login.Alfeus

© 2022 - 2024 — McMap. All rights reserved.