使用Devise和Omniauth编辑用户



我正在通过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(在这种情况下,provider属性将为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用户也是如此(这是有道理的,因为密码字段也不会显示在这些用户的编辑页面上)。

有些人四处打听,确认需要密码?方法返回false,无论是当用户通过OmniAuth还是通过网站的常规用户注册时。即使我将其更改为简单地运行超类方法,它也会返回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

最简单的方法是覆盖RegistrationsController中的update_resource方法。这是由设计人员在自己的控制器实现中建议的:

# By default we want to require a password checks on update.
# You can overwrite this method in your own RegistrationsController.
def update_resource(resource, params)
resource.update_with_password(params)
end

因此,解决方案是在您自己的控制器中覆盖此方法,如下所示:

class Users::RegistrationsController < Devise::RegistrationsController
# Overwrite update_resource to let users to update their user without giving their password
def update_resource(resource, params)
if current_user.provider == "facebook"
params.delete("current_password")
resource.update_without_password(params)
else
resource.update_with_password(params)
end
end
end

我在下面的链接中添加了一个更新,其中包括我对Devise/OmniAuth更改用户配置文件/密码问题的解决方案,并收集了一些有用的链接:

stackoverflow-允许用户在不保存密码的情况下编辑帐户

我在某个地方看到过这个用法。


def update
params[:user].delete(:current_password)
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
if current_user.update_without_password(params[:user])
redirect_to somewhere_wicked_path, notice =>"You rock"
else
render 'edit', :alert =>'you roll'
end
end

在控制器的更新方法中使用类似的方法。很确定这个方法也在Devise中。

最新更新