我正在通过 Railscast 实现 Devise 和 OmniAuth(以及 Devise文档)——目前,我有一个网站,访问者可以使用他们的 Facebook 帐户或填写表格进行注册。
但是,当通过 OmniAuth 注册的用户尝试编辑他们的个人资料时,我遇到了麻烦。Devise 在用户提交个人资料更改时会查找用户的当前密码,但使用 facebook 登录的用户不知道他们的密码(它们在用户模型中自动设置):
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(first_name:auth.extra.raw_info.first_name,
last_name:auth.extra.raw_info.last_name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
user
end
当用户编辑他的信息时,如果他通过 OmniAuth 设置他的帐户,则应用程序不应要求密码确认。本教程建议使用方便的 password_required?方法将帮助我实现这个结果。具体来说,将这个方法添加到用户模型意味着它应该只在用户没有通过 OmniAuth 注册时才返回 true(在这种情况下提供者属性将为 nil):
def password_required?
super && provider.blank?
end
因此,一段代码如下:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<%= render :partial => "essential_user_info_inputs", :locals => { :f => f } %>
<%= render :partial => "inessential_user_info_inputs", :locals => { :f => f } %>
<% if f.object.password_required? %>
<%= render :partial => "password_inputs", :locals => { :f => f } %>
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
<% end %>
<%= f.submit "Update" %>
<% end %>
理论上只会在需要时显示密码输入。它还表明,Devise 内置了逻辑,即 OmniAuth 用户不需要使用密码来编辑他们的帐户。我不知道这是否属实,但教程有点让它看起来像那样。但是当 OmniAuth 用户尝试编辑他的帐户时,我得到“当前密码不能为空”。非 OmniAuth 用户也是如此(这是有道理的,因为密码字段也不会显示在这些用户的编辑页面上)。
一些闲逛确认password_required?当用户通过 OmniAuth 注册和通过站点的常规用户注册时,方法返回 false。即使我将它更改为简单地运行超类方法,它也会返回 false。
关于 password_required 方法发生了什么的任何想法?我在任何地方都找不到任何关于它的信息,但我觉得这就是现在让事情变得糟糕的原因。
更新:
这现在可以工作,但没有使用 Railscast 中概述的方法,它依赖于 requires_password?方法,一个我仍然一无所知的话题。相反,我按照此处的建议实施了此处概述的解决方案。所以我现在只需要密码来使用代码更新非 OmniAuth 帐户:
class Users::RegistrationsController < Devise::RegistrationsController
def update
@user = User.find(current_user.id)
email_changed = @user.email != params[:user][:email]
is_facebook_account = !@user.provider.blank?
successfully_updated = if !is_facebook_account
@user.update_with_password(params[:user])
else
@user.update_without_password(params[:user])
end
if successfully_updated
# Sign in the user bypassing validation in case his password changed
sign_in @user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
end