问题
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.
回答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).
来源:https://stackoverflow.com/questions/30703209/how-to-save-the-request-referrer-for-facebook-omniauth-in-rails-4