设计没有密码的更新用户

时间:2011-02-25 03:22:45

标签: ruby-on-rails devise

我想在设计中更新没有密码的用户属性。情况就像,如果密码和密码确认字段不是空白,那么我需要设计错误,如果它们是空白,则需要更新其他用户属性。我怎么能用设计做到这一点?

提前致谢!

19 个答案:

答案 0 :(得分:84)

我认为这是一个更好的解决方案:

if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
    params[:user].delete(:password)
    params[:user].delete(:password_confirmation)
end

这可以防止您只需从表单响应中删除密码字段即可更改Devise控制器,如果它是空白的。

请确保在 @user.attributes = params[:user]之前使用此或在update操作中使用的任何内容从表单中设置新参数。

答案 1 :(得分:61)

这是你要找的吗?来自Devise wiki

Allow users to edit their account without providing a password

它显示了如何为rails 3和rails 4

执行此操作

=======================

John's solution是一个更简单的替代方案

答案 2 :(得分:18)

我认为使用Devise 3.2+,您可以覆盖子类控制器中的update_resource。以下是最初提出的问题的示例:

class MyRegistrationsController < Devise::RegistrationsController
  protected

  def update_resource(resource, params)
    resource.update_without_password(params)
  end
end

答案 3 :(得分:7)

我解决了这个问题如下:如果表单提交密码,则需要填写current_password字段或表格更新,不带密码和current_password

模特中的

class User
  devise: bla-bla-bla

  attr_accessor :current_password
end

在控制器中:

class Users::RegistrationsController <  Devise::RegistrationsController
  layout 'application'


   def update
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)


    # custom logic
    if params[:user][:password].present?
      result = resource.update_with_password(params[resource_name])
    else
      result = resource.update_without_password(params[resource_name])
    end

    # standart devise behaviour
    if result
      if is_navigational_format?
        if resource.respond_to?(:pending_reconfirmation?) && resource.pending_reconfirmation?
          flash_key = :update_needs_confirmation
        end
        set_flash_message :notice, flash_key || :updated
      end
      sign_in resource_name, resource, :bypass => true
      respond_with resource, :location => after_update_path_for(resource)
    else
      clean_up_passwords resource
      respond_with resource
    end
  end
end

答案 4 :(得分:3)

我用我的界面解决了这个问题。有两种方法可以实现。

如果字段为空,则禁用

这些jQuery在表单提交之前禁用字段,如果它们为空。它需要一定的标记模式,请检查demo on Codepen

$(".password-fields").each(function() {
  var $fields, $form;
  $form = $(this).parents("form");
  $fields = $(this).find("input");
  $form.on("submit", function() {
    $fields.each(function() {
      if ($(this).val() === "") {
        $(this).attr("disabled", "disabled");
      }
    });
  });
});

为用户提供一个复选框,以选择是否要更新

另一个选择是如果用户没有表明他们想要更新密码,则从表单中删除密码字段。这是示例on CodePen

$(".password-fields").each(function () {
  var $fields, $button, html;
  $fields = $(this);
  $button = $fields.prev(".update-password").find("input");
  html = $fields.html();

  $button
    .on("change", function () {
      if ( $(this).is(":checked") ) {
        $fields.html(html);
      }
      else {
        $fields.html("");
      }
    })
    .prop("checked", "checked")
    .click();
});

在任何一种情况下,它都不需要更新应用程序本身。您只是提交要更改的字段。

答案 5 :(得分:3)

我改为覆盖#password_required?用户模型中的方法。

class User < ActiveRecord::Base
  devise :database_authenticatable, :validatable #, ...

  def password_required?
    if respond_to?(:reset_password_token)
      return true if reset_password_token.present?
    end
    return true if new_record?
    password.present? || password_confirmation.present?
  end
end

因此,如果用户是新用户,则需要指定密码。 但是,只有当用户填写password或password_confirmation属性时,才需要指定用户。

有关详细信息,请参阅: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L33

我的实现几乎与原始版本相同: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L53

除了我检查是否存在(对空字符串返回false)

以下是关于此问题的拉取请求的讨论:https://github.com/plataformatec/devise/pull/3920

答案 6 :(得分:3)

如果您仍想支持密码更改但要将其设为可选,请检查current_password的可用性:

class MyRegistrationsController < Devise::RegistrationsController
  protected

  def update_resource(resource, params)
    if params[:current_password].blank?
     resource.update_without_password(params.except(:current_password))
    else
      resource.update_with_password(params)
    end
  end
end

这样,如果current_password存在,您可以继续并更新密码,否则忽略它并在没有密码的情况下更新。

答案 7 :(得分:2)

params [:user] [:password]在rails 6中不起作用

您必须将 params [:user] [:password] 更改为 params [:password]

删除所有参数中的[:user]

我的源代码在下面

在运行此命令之前

  

rails产生devise:controllers用户-c = registrations

class Users::RegistrationsController < Devise::RegistrationsController
  # before_action :configure_sign_up_params, only: [:create]
  # before_action :configure_account_update_params, only: [:update]

  protected

  def update_resource(resource, params)
    puts "params ===> #{params}"
    if params[:password].blank? && params[:password_confirmation].blank?
      params.delete(:password)
      params.delete(:password_confirmation)
      params.delete(:current_password)
      resource.update_without_password(params)
    else
      super
    end
  end
end

答案 8 :(得分:1)

如果您希望Devise仅在用户尝试更改密码时检查当前密码 表示您可以更改其他属性而不提供当前密码 >):

class RegistrationsController < Devise::RegistrationsController

  protected

    def update_resource(resource, params)
      if params[:password].blank? && params[:password_confirmation].blank?
      resource.update_without_password(params)
    else
     super
    end
  end
end

同样在你的模特中:

attr_accessor :current_password

别忘了

devise_for :users, controllers: {registrations: 'registrations'}
routes.rb 中的

答案 9 :(得分:1)

任何在2020年访问的人,这是我发现的最简单的解决方案:

registrations_controller.rb中:

class RegistrationsController < Devise::RegistrationsController

  protected

  def update_resource(resource, params)
    # Require current password if user is trying to change password.
    return super if params["password"]&.present?

    # Allows user to update registration information without password.
    resource.update_without_password(params.except("current_password"))
  end
end

在routes.rb中:

devise_for :users, controllers: {
  registrations: 'users/registrations'
}

可归功于:西口正俊

https://www.mnishiguchi.com/2017/11/24/rails-devise-edit-account-without-password/

答案 10 :(得分:1)

对于未来的Google员工,我花了3个小时在这里,这对我有用。

在我的用户模型中,仅当密码和password_confirmation存在时,我删除:validatable并添加了validates方法:

class User < ApplicationRecord
  devise :database_authenticatable, :registranable, recoverable, :rememberable
    
  validates :password, length: { in: 6..128 }, if: lambda {self.password.present?}
  validates_confirmation_of :password, if: lambda {self.password.present?}
end

然后在users_controller的更新方法中,如果密码和password_confirmation参数为空,则将它们删除

class UsersController > ApplicationController
  def update
    if params[:user][:password].blank?
      params[:user].delete(:password)
      params[:user].delete(:password_confirmation)
    end

    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: 'User was successfully updated' }
      else
        format.html { render :edit }
      end
    end
  end
end

Devise复杂的做事方式使事情变得简单,简单,轻松且无所不包。

不客气。

答案 11 :(得分:0)

如果您真的想在没有 current_password 的情况下更新密码,那么您需要使用用户 reset_password 方法

@user.reset_password(params[:user][:password], params[:user][:password_confirmation])

以下是适用于所有场景的问题的完整可行解决方案:

  if params.dig(:user, :password).blank?
    updated = @user.update_without_password(params[:user].to_unsafe_hash)
  else
    if params.dig(:user, :current_password).nil?
      @user.reset_password(params[:user][:password], params[:user][:password_confirmation])

      updated = @user.update_without_password(params[:user].to_unsafe_hash)
    else
      updated = @user.update_with_password(params[:user].to_unsafe_hash)
    end

    bypass_sign_in(@user)
  end

答案 12 :(得分:0)

要更新用户的属性,您将需要使用:current_password,以检查“您的用户使用了正确的current_password还是有人想破坏您的用户”

所以形式:

= f.input :current_password,
          hint: "we need your current password to confirm your changes",
          required: true,
          input_html: { autocomplete: "current-password" }

在控制器中:

    if your_user.valid_password?(params[:user][:current_password])
        your_user.update_attributes(user_params.except(:current_password, :password, :password_confirmation))
    end

第一行检查“您的用户是否发送了正确的密码”,然后我们就可以更新属性而不会产生垃圾

答案 13 :(得分:0)

更好和更简短的方法:将检查参数添加到user_params块中。 例如:

def user_params
    up = params.require(:user).permit(
      %i[first_name last_name role_id email encrypted_password
         reset_password_token reset_password_sent_at remember_created_at
         password password_confirmation]
    )

    if up[:password].blank? && up[:password_confirmation].blank?
      up.delete(:password)
      up.delete(:password_confirmation)
    end
    up
end

答案 14 :(得分:0)

在对上述可能性进行了大量探索之后,我终于找到了一个解决方案,它允许您在没有密码的情况下更新某些属性,其中一些包含:

我为user / edit.html.erb制作了一个视图,其中包含以下表单。

<%= form_for(@user) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.submit "Save changes"%>
<% end %>

我在routes.rb中设置路线

resources :users, only: [:show, :index, :edit, :update]

我在users_controller.rb中编辑和更新了方法

def edit
  @user = current_user
end

def update
  @user = current_user
  if @user.update_attributes(user_params)
    flash[:success] = "Profile updated"
    redirect_to root_url
  else
    render 'edit'
  end
end


def user_params
  params.require(:user).permit(:name, :avatar, :whatsup)
end

我使用此编辑视图进行不需要密码的更改。它完全跳过设计注册控制器,因为我用

链接到它
edit_user_path(current_user)

我还设置了参数,以便在此处无法更改电子邮件和密码。要更新密码和电子邮件,我链接到库存生成设计视图:

edit_user_registration_path(current_user)

我承认这是一个巨大的工作,但没有一个更简单的解决方案解决了上述所有问题。

答案 15 :(得分:0)

我发现以上代码的这种轻微变化更容易理解:

def update
  @user = User.find(params[:id])

  method = if user_params[:password].blank?
             :update_without_password
           else
             :update_with_password

  if @user.send(method, user_params)
    redirect_to @user, notice: 'User settings were saved.'
  else
    render :edit
  end
end

答案 16 :(得分:0)

将解决方法放入用户模型

def password_required?
  encrypted_password.blank? || encrypted_password_changed?
end

答案 17 :(得分:0)

我有完全相同的问题,这是我提出的解决方案并相信我的工作原理。 我做的是创建第二个user_params方法,并命名为user_params_no_pass无论如何看看:这里发生的是管理员将在需要更新密码时提供密码,否则将密码留空。如果密码为空,则使用user_params_no_pass,否则使用user_params。我希望有帮助

    def update

    if @user.valid_password?(params[:user][:password])
          respond_to do |format|

            if @user.update(user_params)
              format.html { redirect_to @user, notice: 'User profile was successfully updated.' }
              format.json { render :show, status: :ok, location: @user }
            else
             format.html { render :new }
             format.json { render json: @user.errors, status: :unprocessable_entity }
            end
          end
    else
      respond_to do |format|

            if @user.update(user_params_no_pass)
              format.html { redirect_to @user, notice: 'User profile was successfully updated without password.' }
              format.json { render :show, status: :ok, location: @user }
            else
              format.html { render :edit }
              format.json { render json: @user.errors, status: :unprocessable_entity }
            end
          end
    end
  end

  def destroy
     @user.destroy
      respond_to do |format|
        format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
        format.json { head :no_content }
      end
  end
  private

    def set_user
      @user = User.find(params[:id])
    end

    def user_params
      params.require(:user).permit(:user_name, :first_name, :middle_name, :last_name, :dob, :gender, :race, :hispanic, :leader, :mentor, :student, :email, :organization_id, :password, :opus,
  :release_date, :days_to_release, :current_level, :is_active)
    end


    def user_params_no_pass
      params.require(:user).permit(:user_name, :first_name, :middle_name, :last_name, :dob, :gender, :race, :hispanic, :leader, :mentor, :student, :email, :organization_id, :opus,
  :release_date, :days_to_release, :current_level, :is_active)
    end

答案 18 :(得分:0)

它有更多的业务逻辑,所以我不会在控制器中放入太多代码。我建议在模型中覆盖Devise::Models::Validatable#password_required?

def password_required?
  new_record? || password.present? || password_confirmation.present?
end