ruby-on-rails – 使用Devise和Omniauth编辑用户

我正在通过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

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...