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

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

我的应用程序中有两个 Facebook 按钮。一个在 users/sign_up 上,另一个在 /visitors/owner-faq 上。我想保存 request.referrer 以便了解用户是从哪个页面注册的。我已经为外部注册(使用表单)实现了相同的方法并且它有效。现在我无法为 facebook omniauth.

实现相同的功能

代码:

#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

尝试 #1:

我设法在 users/omniauth_callbacks_controller

中像这样保存了 request.referrer
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

但是这里的问题是referrer_url的值在现有用户登录时被覆盖来自另一页。我不想让 referrer_url 被覆盖。

尝试#2:

我试过在 from_omniauth(auth) 方法 User 模型中保存 request.referrer 像这样

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

但是它给了我这个错误

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

任何建议都会很有帮助。

如果您希望 referrer_url 属性 在首次设置后保持不变,您应该使用 OR Equal 运算符,它只会设置当前为 nilfalse:

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

如果我没理解错的话,你的 facebook 回调在注册和登录时都会被调用,当然这个值会被覆盖。 OR Equals 将防止值在设置后被覆盖。

关于尝试 #2,会话哈希仅可用 in the controller and the view,因此您不能在模型中使用它。

另一种可能:

您正在 store_referrer_url 方法中设置 session[:referrer],该方法在 new 方法的 before_filter 回调中调用。

很可能您的登录也是使用 new 方法进行的(例如,使用 Devise 它将在 SessionsController 中),因此再次调用回调并覆盖值(所有设计控制器继承自您的 ApplicationController)。在这种情况下,您可以从 ApplicationController 中取出 before_filter 回调到您正在处理注册的控制器(使用 Devise 时将是 RegistrationsController)。