program story

비밀번호없이 업데이트 사용자 고안

inputbox 2020. 10. 23. 07:52
반응형

비밀번호없이 업데이트 사용자 고안


비밀번호없이 사용자 속성을 업데이트하고 싶습니다. 이 경우는 암호 및 암호 확인 필드가 비어 있지 않으면 고안 오류가 필요하고 비어 있으면 다른 사용자 속성을 업데이트해야합니다. devise로 어떻게 할 수 있습니까?

미리 감사드립니다!


이것이 당신이 찾는 것입니까? Devise 위키에서

사용자가 비밀번호를 제공하지 않고 계정을 편집 할 수 있도록 허용

레일 3 및 레일 4에 대해 수행하는 방법을 보여줍니다.

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

John의 솔루션 은 더 간단한 대안입니다.


나는 이것이 훨씬 더 나은 해결책이라고 생각합니다.

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양식에서 새로운 매개 변수를 설정하는 액션입니다.


Devise 3.2 이상에서는 하위 클래스 컨트롤러에서 update_resource를 재정의 할 수 있다고 생각합니다. 다음은 원래 질문에 대한 예입니다.

class MyRegistrationsController < Devise::RegistrationsController
  protected

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

이 문제를 다음과 같이 해결했습니다. 양식을 비밀번호로 제출하는 경우 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

내 인터페이스로이 문제를 해결합니다. 두 가지 방법이 있습니다.

필드가 비어있는 경우 비활성화

이 jQuery 비트는 비어있는 경우 양식이 제출되기 전에 필드를 비활성화합니다. 특정 마크 업 패턴이 필요합니다 . 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");
      }
    });
  });
});

사용자에게 업데이트를 원하는지 선택할 수있는 확인란을 제공합니다.

또 다른 옵션은 사용자가 암호 업데이트를 원한다고 표시하지 않은 경우 양식에서 암호 필드를 제거하는 것입니다. 다음 은 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();
});

두 경우 모두 앱 자체에 대한 업데이트가 필요하지 않습니다. 변경하려는 필드를 제출하는 것입니다.


대신 #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


여전히 암호 변경을 지원하고 싶지만 선택 사항으로 설정하려면 다음 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가있는 경우 계속해서 암호를 업데이트 할 수 있습니다. 그렇지 않으면 무시하고 암호없이 업데이트 할 수 있습니다.


사용자가 비밀번호를 변경하려고 할 때만 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 .


사용자 모델에있는 해결 방법

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

params [: user] [: password]가 rails 6에서 작동하지 않습니다.

params [: user] [: password]params [: password] 로 변경해야 합니다.

모든 매개 변수에서 [: user] 제거

내 소스 코드는 다음과 같습니다.

이 명령을 실행하기 전에

rails는 devise를 생성합니다 : controllers users -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

더 많은 비즈니스 로직이므로 컨트롤러에 너무 많은 코드를 넣지 않을 것입니다. Devise::Models::Validatable#password_required?모델에서 재정의 하는 것이 좋습니다 .

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

나는 똑같은 문제가 있었고 이것이 내가 생각해 낸 해결책이며 작동한다고 믿습니다. 내가 한 일은 두 번째 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

I find this slight variation on the code above easier to follow:

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

After much exploration of the above possibilities I finally found a solution which allows you to update some attributes without a password and some with:

I made a view for user/edit.html.erb with the following form in it.

<%= 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 %>

I set routes in routes.rb

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

I made edit and update methods in 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

I used this edit view for changes which did not require a password. It skips the devise registration controller entirely because I link to it with

edit_user_path(current_user)

I also set the params so that email and password cannot be changed here. To update password and email, I link to the stock generated devise view:

edit_user_registration_path(current_user)

I admit that this is a huge work around but none of the simpler solutions solved all of the above problems.


Better and short way: add check params into the user_params block. For example:

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

to update attributes for user, you will need to use :current_password, to check 'do your user use correct current_password or someone wants to break your user'

so in form:

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

in controller:

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

the first line checks 'do your user sends the correct password or not', and then we can to update the attributes without garbage

참고URL : https://stackoverflow.com/questions/5113248/devise-update-user-without-password

반응형