过去一直采用纯 oauth 方式登录,今天增加了邮件密码方式登录。 方案很标准 mongodb+devise+omniauth
由于直接通过 oauth 方式登录的话是不会填写邮箱和密码的,所以 email 和 password 字段都为空。 通过 oauth 方式注册用户的代码:
def create_from_omniauth(data)
create do |user|
auth = Auth.from_omniauth(data)
user.auths << auth
user.name = auth.nickname
user.remote_avatar_url = auth.parse_image(data)
end
end
有关的 oauth 回调代码
user = User.create_from_omniauth(omniauth)
user.update_from_omniauth(omniauth)
sign_in user
redirect_to edit_user_registration_path(:new => true)
要注意的是:由于 devise 的 validatable 的限制,email 和 password 都是必填,所以按道理这个 create 是一定失败的,但是奇迹的是,保存确实成功了! 经过调试,create 确实没保存成功,但是调用过 sign_in 方法后,user 被持久化了,于是顺着 sign_in 一路查阅源码没有任何可疑的地方。。。
@lilu 突然提到,可能是 trackable 的问题,查阅源码,果然发现。。。
def update_tracked_fields!(request)
old_current, new_current = self.current_sign_in_at, Time.now.utc
self.last_sign_in_at = old_current || new_current
self.current_sign_in_at = new_current
old_current, new_current = self.current_sign_in_ip, request.remote_ip
self.last_sign_in_ip = old_current || new_current
self.current_sign_in_ip = new_current
self.sign_in_count ||= 0
self.sign_in_count += 1
save(:validate => false) or raise "Devise trackable could not save #{inspect}." \
"Please make sure a model using trackable can be saved at sign in."
end
在更新 track 的时候,会禁用 validation,所以造成了上述问题,顺便看了下其他模块的代码,使用 save:validate => false 很频繁。
所以,如果因为一些原因要自己处理登录逻辑,调用sign_in
之前,一定要确保对象的状态。
PS:这个问题很久前已经有人提issue 了,但是作者的回答完全不着边际 PS2:去济南的时候 @lgn21st 说过,能搞懂 devise 的绝对不是一般人... PS3:其实自从看到 omniauth 的设计后,就被深深吸引了,推荐大家放弃复杂的 devise...虽然他很省事,但是需要实现一些用户系统的高级功能的时候,要考虑下自己能不能驾驭他...