Как сохранить request.referrer для facebook omniauth в 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:

Мне удалось сохранить 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.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

Но это дало мне эту ошибку

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

Любые предложения будут очень полезны.


person Pavan    schedule 08.06.2015    source источник
comment
удалить :only => [:new] в контроллере приложений. обычно вы хотите сделать это только в других контроллерах. это наиболее вероятная причина, по которой вы не получаете никакого реферера с omniauth.   -  person jvnill    schedule 08.06.2015


Ответы (1)


Если вы хотите, чтобы свойство referrer_url оставалось неизменным после его первой установки, вам следует использовать OR Equal, который установит значение только в том случае, если в настоящее время оно равно nil или false:

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

Если я правильно понимаю, ваш обратный вызов facebook вызывается как при регистрации, так и при входе в систему, и, конечно, значение будет перезаписано. ИЛИ Equals предотвратит перезапись значения после его установки.

Что касается попытки №2, хэш сеанса доступен только в контроллере и view, поэтому вы не можете использовать его в модели.

Другой вариант:

Вы устанавливаете session[:referrer] в методе store_referrer_url, который вызывается в обратном вызове before_filter в методе new.

Скорее всего, ваш вход в систему также осуществляется с помощью метода new (например, с Devise это будет SessionsController), поэтому обратный вызов вызывается снова, и значение перезаписывается (все контроллеры Devise наследуются от вашего ApplicationController). В этом случае вы можете вывести обратный вызов before_filter из ApplicationController на контроллер, на котором вы обрабатываете регистрацию (будет RegistrationsController с Devise).

person p4sh4    schedule 08.06.2015
comment
Он по-прежнему перезаписывает referrer_url после изменения на session[:referrer] ||= URI(request.referer).path - person Pavan; 08.06.2015
comment
Ой, моя ошибка, пожалуйста, посмотрите правку. Конечно, session[:referrer] будет вычищен. Вы также можете поместить строку @user.referrer_url = session[:referrer] внутри строки if @user.persisted? и снова сохранить объект, чтобы он не устанавливался при входе в систему. - person p4sh4; 08.06.2015