我正在通过Railscast实施Devise和OmniAuth(与Devise
documentation一起) – 目前,我有一个网站,访问者可以使用他们的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用户相同(这是有道理的,因为密码字段也不会显示在这些用户的编辑页面上).
有些戳戳确认password_required?当用户通过OmniAuth注册并通过站点的常规用户注册时,方法返回false.即使我更改它只是运行超类方法,它返回false.
任何关于password_required方法发生什么的想法?我在任何地方找不到任何东西,但我觉得这是现在的事情.
更新:
这是现在工作,但不使用Railscast中概述的方法,它依赖于require_password?方法,一个我仍然不了解的话题.相反,我实施了here所示的here解决方案.所以我现在只需要密码来更新非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