0

我的应用程序中有两个 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:

我设法保存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

但是这里的问题是,当现有用户从另一个页面登录时,值会referrer_url覆盖。我不想让被覆盖。referrer_url

尝试#2:

我试图像这样request.referrerfrom_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

但它给了我这个错误

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

任何建议都会很有帮助。

4

1 回答 1

1

如果您希望referrer_url属性在第一次设置后保持不变,您应该使用OR Equal运算符,它只会在当前为nilor时设置值false

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

如果我理解正确,您的facebook回调在注册和登录时都会被调用,当然该值会被覆盖。OR Equals 将防止该值在设置后被覆盖。

关于尝试 #2,会话哈希仅在控制器和视图中可用,因此您不能在模型中使用它。

另一种可能性

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

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

于 2015-06-08T07:29:23.223 回答