红宝石在轨道上
我在Ruby on Rails上使用Devise + OAuth。
我已经修改了ApplicationController中的after_sign_in_path,如下所示:
def after_sign_in_path_for(resource)
if session[:longitude]
puts user_signed_in?
new_questionnaire_path
else
super
end
end
当它被调用时,日志输出:
true
Redirected to http://localhost:3000/questionnaires/new
我对新调查问卷的路线有以下几点:
def require_login
unless current_user
redirect_to new_user_registration_path, notice: 'Please sign in to get started!'
end
end
用户第一次通过OAuth登录时,current_user以某种方式变为零,并且日志显示以下内容:
Started GET "/questionnaires/new" for 127.0.0.1 at 2018-01-06 17:30:50 -0800
Processing by QuestionnairesController#new as HTML
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL
ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
Redirected to http://localhost:3000/users/sign_up
Filter chain halted as :require_login rendered or redirected
如果用户再次登录,它们将被重定向到new_questionnaire_path,并且不会再次点击before_action。
为什么会发生这种情况?
编辑:这是我的OmniAuthCallbacksController的内容。 我不认为这是相关的,因为after_sign_in_path_for(resource)在sign_in_with(provider_name)之后被调用,但也许我错过了一些东西?
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def sign_in_with(provider_name)
@user = User.from_omniauth(request.env["omniauth.auth"])
@user.profile
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => provider_name) if
is_navigational_format?
end
def facebook
sign_in_with "Facebook"
end
def linkedin
sign_in_with "LinkedIn"
@user.linked_in_data = request.env["omniauth.auth"]
@user.save
@profile = Profile.find_by_user_id(@user.id)
@profile.first_name = @user.linked_in_data['info']['first_name']
@profile.last_name = @user.linked_in_data['info']['last_name']
@profile.title = @user.linked_in_data['info']['description']
@profile.industry = @user.linked_in_data['extra']['raw_info']['industry']
@profile.save
end
def twitter
sign_in_with "Twitter"
end
def google_oauth2
sign_in_with "Google"
end
def developer
sign_in_with "Developer"
end
end
您需要遵循oauth设计实现的说明。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
@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"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
我想问你,你在哪里找到这个代码。 主要的问题是,在User.from_omniauth
之后我没有看到error handling
的逻辑,所以也许有些东西在那里失败并且不会触发错误。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def sign_in_with(provider_name)
@user = User.from_omniauth(request.env["omniauth.auth"])
@user.profile
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => provider_name) if
is_navigational_format?
end
我无法深入了解您的问题(登录后重定向),因为我觉得您的逻辑错误。 例如,如果您使用def linkedin
log in
,即使用户未注册,我也将始终运行@profile.first_name
和@profile.save
,但使用@user = User.from_omniauth(request.env["omniauth.auth"])
def linkedin
sign_in_with "LinkedIn"
@user.linked_in_data = request.env["omniauth.auth"]
@user.save
@profile = Profile.find_by_user_id(@user.id)
@profile.first_name = @user.linked_in_data['info']['first_name']
@profile.last_name = @user.linked_in_data['info']['last_name']
@profile.title = @user.linked_in_data['info']['description']
@profile.industry = @user.linked_in_data['extra']['raw_info']['industry']
@profile.save
end
这是self.from_omniauth(auth)
方法
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.name = auth.info.name # assuming the user model has a name
user.image = auth.info.image # assuming the user model has an image
# If you are using confirmable and the provider(s) you use validate emails,
# uncomment the line below to skip the confirmation emails.
# user.skip_confirmation!
end
end
我能够通过根据Fabrizio的建议添加错误处理来解决此问题,该建议显示@ user.persisted? 正在返回假。
puts @ user.errors.to_a告诉我“密码不能为空”,我没有意识到是这种情况,所以我在user.password = Devise.friendly_token [0,20]中加入了self.from_omniauth方法我的用户模型,解决了这个问题。
我仍然不完全明白的是,如何将用户添加到数据库而同时@ user.persisted? 正在返回假。
下面显示的是我更新后的控制器,包括错误处理,我用来查找问题来源的puts语句,以及代码,仅针对Fabrizio的出色建议的第一个签名执行Profile更新。
具有特别敏锐眼光的读者也可能会注意到,sign_in_with方法中的“@ user.profile”行已被删除。 这个方法用于在用户初次注册时为用户创建一个配置文件,但是我意识到将它作为用户模型中的after_create方法做得更干净,所以我也这样做了。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def sign_in_with(provider_name)
@user = User.from_omniauth(request.env["omniauth.auth"])
puts @user.errors.to_a
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => provider_name) if is_navigational_format?
else
session["devise.#{provider_name}_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def facebook
sign_in_with "Facebook"
end
def linkedin
sign_in_with "LinkedIn"
@user.linked_in_data = request.env["omniauth.auth"]
@user.save
if @user.sign_in_count == 1
@profile = Profile.find_by_user_id(@user.id)
@profile.first_name = @user.linked_in_data['info']['first_name']
@profile.last_name = @user.linked_in_data['info']['last_name']
@profile.title = @user.linked_in_data['info']['description']
@profile.industry = @user.linked_in_data['extra']['raw_info']['industry']
@profile.save
end
end
def twitter
sign_in_with "Twitter"
end
def google_oauth2
sign_in_with "Google"
end
def developer
sign_in_with "Developer"
end
def failure
redirect_to root_path
end
end
链接地址: http://www.djcxy.com/p/47451.html
上一篇: ruby on rails