如何在 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 运算符,它只会设置当前为 nil
或 false
:
@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
)。
我的应用程序中有两个 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 运算符,它只会设置当前为 nil
或 false
:
@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
)。