简体   繁体   English

如何在Rails 4中为Facebook omniauth保存request.referrer

[英]How to save the request.referrer for facebook omniauth in Rails 4

I have two facebook buttons in my application. 我的应用程序中有两个Facebook按钮。 One on users/sign_up and other on /visitors/owner-faq . 一个在users/sign_up ,另一个在/visitors/owner-faq I want to save the request.referrer in order to know from which page the user has signed up. 我想保存request.referrer以便知道用户从哪个页面进行了注册。 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 . 现在,我无法为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: 尝试1:

I managed to save the request.referrer like this in users/omniauth_callbacks_controller 我设法将request.referrer这样保存在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 . 但是这里的问题是,当现有用户从另一个页面登录时, referrer_url的值将被覆盖 I don't want to get the referrer_url to be overwritten. 我不想覆盖referrer_url

Attempt #2: 尝试2:

I tried to save the request.referrer in the from_omniauth(auth) method User model like this 我试图将request.referrer保存在from_omniauth(auth)方法User模型中,如下所示

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. 任何建议将大有帮助。

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 : 如果希望referrer_url属性在首次设置后保持不变,则应使用OR Equal运算符,该运算符只会在当前值为nilfalse设置该值:

@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. 如果我理解正确,那么在注册和登录时都会调用您的facebook回调,并且该值当然会被覆盖。 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. 关于尝试2 ,会话哈希仅在控制器和视图中可用,因此您不能在模型中使用它。

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. 您要在store_referrer_url方法中设置session[:referrer]store_referrer_url方法在new方法的before_filter回调中调用。

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 ). 您的登录很有可能也是使用new方法进行的(例如,在Devise中,它将在SessionsController ),因此再次调用该回调并覆盖该值(所有Devise控制器都继承自您的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). 在这种情况下,您可以从ApplicationController取出before_filter回调到正在处理RegistrationsController的控制器(将是带有Devise的RegistrationsController )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM