【问题标题】:Ruby on Rails, Devise gem. How to remove current password when password is blank?Ruby on Rails,设计宝石。密码为空时如何删除当前密码?
【发布时间】:2011-02-05 15:14:47
【问题描述】:

现在我意识到这个话题之前已经讨论过很多次了。但是,似乎没有解决方案希望仅当数据库中的密码为空时才使当前密码字段免除。

我目前有我的用户模型所需的密码,例如:

def password_required?
  (authentications.empty? || !password.blank?) && super
end

然后我将更新功能复制到我的注册控制器中:

def update
  if resource.update_with_password(params[resource_name])
    set_flash_message :notice, :updated
    sign_in resource_name, resource, :bypass => true
    redirect_to after_update_path_for(resource)
  else
    clean_up_passwords(resource)
    render_with_scope :edit
  end
end

我只是不知道如何确保在编辑空白密码时设备不需要密码,我是否还需要从视图中删除 current_password 字段并执行此操作?

<% if current_user.password_required? %>
  <p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
  <%= f.password_field :current_password %></p>
<% end %>
<p><%= f.submit "Update" %></p>

任何建议都会很好,因为我确信我忽略了一些东西,但我对 Rails 整体还是新手。谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 passwords devise


    【解决方案1】:

    好的,我终于想通了!

    将以下内容添加到您的类 RegistrationsController

    def update
      if resource.update_with_password(params[resource_name])
        set_flash_message :notice, :updated
        sign_in resource_name, resource, :bypass => true
        redirect_to after_update_path_for(resource)
      else
        clean_up_passwords(resource)
        render_with_scope :edit
      end
    end
    

    然后将以下内容添加到您的用户模型中:

    def update_with_password(params={})
      current_password = params.delete(:current_password) if !params[:current_password].blank?
    
      if params[:password].blank?
        params.delete(:password)
        params.delete(:password_confirmation) if params[:password_confirmation].blank?
      end
    
      result = if has_no_password?  || valid_password?(current_password)
        update_attributes(params) 
      else
        self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
        self.attributes = params
        false
      end
    
      clean_up_passwords
      result
    end
    
    def has_no_password?
      self.encrypted_password.blank?
    end
    

    我唯一有点困惑的是在编辑视图中:

    <% if !current_user.has_no_password? %>
    

    我把它包裹起来,如果,我会认为它会是:

    <% if current_user.has_no_password? %>
    

    如果有人可以看到任何可以改进我的代码或不同的、更有效的方法,请告诉我!

    【讨论】:

    • current_user.has_no_password? 如果没有密码则返回true,因此 if 语句会执行其块。您正在使用否定语言来验证该声明...您应该写unless current_user.has_no_password?,但它仍然读起来很有趣。如果您执行current_user.has_password? 并将定义设置为返回self.encrypted_password.present?,它会更容易阅读(我意识到这已经在下面讨论过,但这属于 cmets,我给出了一个替代的、更易读的解决方案)
    • 我用它作为其他东西的基础,它非常有效。唯一的改变:我必须删除if !params[:current_password].blank?以避免出现批量分配错误,因为当前密码被设置为""(因此blank? == true)所以没有从参数中删除,然后update_attributes(params)尝试使用:current_password =&gt; "" 更新用户记录 - 显然失败了,因为current_password 不是用户的属性......也许我有错误的一端? selfs 也不是多余的吗?
    • 我试过这个解决方案,我得到 Can't mass-assign protected attributes: current_password
    • @wulftone 我认为根据这个理由,您最终每次都会为所有布尔返回方法创建两个版本的方法。做人讨厌除非。有些人讨厌负数。当它是一个布尔结果时,您是否主要使用一种方法,然后无论如何命名它,以便它在大多数情况下都是正确的。但是如果你同时使用这两个结果,那么我认为定义一个新的方法是最麻烦的。
    【解决方案2】:

    关于是否需要当前密码字段的另一个非常小的更改:我的目标是永远不需要当前密码,除非他们正在更新他们的密码。对于 oauth'ed 帐户,我会在视图中检查 facebook id,并且根本不显示密码字段。

    在注册控制器中:

    Users::RegistrationsController < Devise::RegistrationsController
    
    def update
    
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
    
       if resource.update_with_password(params[resource_name])
         set_flash_message :notice, :updated if is_navigational_format?
         sign_in resource_name, resource, :bypass => true
         respond_with resource, :location => after_update_path_for(resource)
       else
         clean_up_passwords(resource)
         respond_with_navigational(resource){ render_with_scope :edit }
       end
    
    
    end
    

    在 User.rb 中,我使用 update_with_password,然后仅当用户在视图中的密码字段中输入了某些内容时才调用 verify_password_and_update。否则,我清除当前密码参数并调用 update_without_password (这个方法也是内置的):

    #to remove the current password check if updating a profile originally gotten via oauth (fb, twitter)
    
    
      def update_with_password(params={})
        if params[:password].blank?
          params.delete(:current_password)
          self.update_without_password(params)
        else
          self.verify_password_and_update(params)
        end
      end
    
      def update_without_password(params={})
    
        params.delete(:password)
        params.delete(:password_confirmation)
        result = update_attributes(params)
        clean_up_passwords
        result
      end
      def verify_password_and_update(params)
        #devises' update_with_password 
        # https://github.com/plataformatec/devise/blob/master/lib/devise/models/database_authenticatable.rb
        current_password = params.delete(:current_password)
    
        if params[:password].blank?
          params.delete(:password)
          params.delete(:password_confirmation) if params[:password_confirmation].blank?
        end
    
        result = if valid_password?(current_password)
          update_attributes(params)
        else
          self.attributes = params
          self.valid?
          self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
          false
        end
    
        clean_up_passwords
        result
      end
    

    【讨论】:

    • 非常感谢您分享您的代码。我被困了一段时间,看到你的代码有帮助=)
    猜你喜欢
    • 1970-01-01
    • 2017-06-03
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    相关资源
    最近更新 更多