Devise 3 (рельсы 4) не может обновлять пользователя без пароля

Я пытаюсь обновить пользователя, не предоставляя пароль, но подходы, которые работали над более старыми версиями devise/rails, больше не работают с конструкцией 3 и 4-мя сильными параметрами.

Я использую мой user_controller для обновления, но я также попытался использовать специальный контроллер регистрации разработки с devise_parameter_sanitizer без успеха.

Форма не требует пароля (не имеет поля пароля), а user_controller, обрабатывающий обновление, выглядит так:

# PATCH/PUT /users/1
def update
  if user_params[:password].blank?
    Rails.logger.info "entered if statement"
    user_params.delete :password
    user_params.delete :password_confirmation
    Rails.logger.info(user_params.inspect)
  end
  @user = current_user
  if @user.update(user_params)
    redirect_to @user, notice: 'User was successfully updated.'
  else
    Rails.logger.info(@user.errors.inspect) 
    render action: 'edit'
  end
end

private

def user_params
  params.require(:user).permit(:screen_name, :full_name, :email, :about, 
    :location, :profile_pic, :password, :password_confirmation, :current_password)
end

.. журнал после представления выглядит следующим образом:

Started PATCH "/users/13" for 127.0.0.1 at 2013-05-29 11:18:18 +0100
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"20avah2OzaOVubAiam/SgvbYEQ4iijEWQqmNo7xD4rY=", "user"=>{"screen_name"=>"Darcbar", "full_name"=>"Barry Darcy", "about"=>"", "location"=>"", "website_url"=>"", "twitter_username"=>"", "email"=>"[email protected]"}, "commit"=>"Save changes", "id"=>"13"}
User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 13 ORDER BY "users"."id" ASC LIMIT 1

Entered if statement...
{"screen_name"=>"Darcbar", "full_name"=>"Barry Darcy", "email"=>"[email protected]", "about"=>"", "location"=>"", "twitter_username"=>"", "website_url"=>""}

(0.2ms)  BEGIN
User Exists (0.8ms)  SELECT 1 AS one FROM "users" WHERE ("users"."email" = '[email protected]' AND "users"."id" != 13) LIMIT 1

(0.2ms)  ROLLBACK
#<ActiveModel::Errors:0x007fedf45bb640 @base=#<User id: 13, username: "darcbar", full_name: "Barry Darcy", about: "", location: "", email: "[email protected]", encrypted_password: "$2a$10$Mb4zsRPPqZ9CYz0zdLMBU.62NyIk/T8s6Zw/uRTwWov3...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 9, current_sign_in_at: "2013-05-28 17:51:20", last_sign_in_at: "2013-05-28 16:42:52", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", authentication_token: nil, created_at: "2013-05-27 14:03:41", updated_at: "2013-05-28 17:51:20", screen_name: "Darcbar", profile_pic_file_name: nil, profile_pic_content_type: nil, profile_pic_file_size: nil, profile_pic_updated_at: nil>, 
  @messages={:password=>["please enter a password with at least 5 characters", "please enter a password with at least 5 characters"]}>

Rendered users/edit.html.haml within layouts/application (3.0ms)
Rendered partials/head/_user_options.haml (1.8ms)
Completed 200 OK in 74ms (Views: 12.1ms | ActiveRecord: 1.7ms)

Кто-нибудь знает, почему ошибки пароля присутствуют?

Ответ 1

Проверка пароля происходит из пользовательской модели:

validates :password, presence: true

Решение состоит в том, чтобы проверять наличие при создании и allow_blank при обновлении:

validates :password, presence: true, length: {minimum: 5, maximum: 120}, on: :create
validates :password, length: {minimum: 5, maximum: 120}, on: :update, allow_blank: true

Ответ 2

Начиная с 2014 года вы можете просто переопределить защищенный метод и выполнить:

class RegistrationsController < Devise::RegistrationsController

  protected

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

Ответ 3

Вы можете использовать метод @user.update_without_password(user_params) для обновления других полей.

Например, у меня это есть в моих пользовательских users_controller.rb. Я обновляюсь с помощью удаленного вызова (ajax).

#users_controller.rb

def update
  respond_to do |format|
    if needs_password?(@user, user_params)
      if @user.update_with_password(user_params_password_update)
        flash[:success] = 'User was successfully updated. Password was successfully updated'
        format.js {render 'update'}
      else
        error = true
      end
    else
      if @user.update_without_password(user_params)
        flash[:success] = 'User was successfully updated.'
        format.js {render 'update'}
      else
        error = true
      end
    end

    if error
      flash[:error] = @user.errors.full_messages.join(', ')
      format.js {render json: @user.errors.full_messages, status: :unprocessable_entity}
    end
  end
end

private

def needs_password?(user, user_params)
  !user_params[:password].blank?
end

def user_params
  params[:user].permit(:email, :password, :password_confirmation, :username, :full_name)
end

#Need :current_password for password update
def user_params_password_update
  params[:user].permit(:email, :password, :password_confirmation, :current_password, :username, :full_name)
end

Ответ 4

Ключ находится в этом "user_params [: password].blank?". Следующий пример кода:

def update
  if user_params[:password].blank?
    params = user_params_without_password
  else
    params = user_params
  end

  respond_to do |format|
    if @user.update(params)
      format.html { redirect_to @user, notice: t(:user_update) }
      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

private

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

# Never trust parameters from the scary internet, only allow the white list through.
def user_params
  params.require(:user).permit(:email, :username, :first_name, :last_name, :admin, :locked, :password)
end

def user_params_without_password
  params.require(:user).permit(:email, :username, :first_name, :last_name, :admin, :locked)
end

Надеемся, что вы поможете

Ответ 5

Я много лет обходил круги. Ответы все можно утверждать, как указано выше mrstif. Если вы используете модуль validatable, Devise работает из коробки (с параметрами конфигурации), позволяя вам обновлять данные пользователя, не указывая пароль, поэтому будьте очень осторожны при проверке собственных паролей.

Ответ 6

просто переопределите конструкцию, создав приложение/контроллер/registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController

  protected
  def update_resource(resource, params)
    resource.update(params.except(:current_password))
  end
end

этот код будет непосредственно обновлять параметры пользователя, кроме: current_password

и обновить config/routes.rb

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

Ответ 7

Моя цель состояла в том, чтобы разрешить редактирование пользовательских атрибутов, не требуя пароля, если только это не изменяет адрес электронной почты, пароль или не удаляет учетную запись. И вот, что сработало для меня:

приложение/контроллеры/registrations_controller.rb:

class RegistrationsController < Devise::RegistrationsController
  before_action :configure_permitted_parameters

  ...

  def update
    params[:user][:team_attributes][:id] = current_user.team.id
    account_update_params = devise_parameter_sanitizer.sanitize(:account_update)

    if password_required?
      successfully_updated = resource.update_with_password(account_update_params)
    else
      account_update_params.delete(:current_password)
      successfully_updated = resource.update_without_password(account_update_params)
    end

    if successfully_updated
      sign_in resource, bypass: true
      redirect_to '/'
    else
      render :edit
    end
  end

  def destroy
    current_password = devise_parameter_sanitizer.sanitize(:account_update)[:current_password]
    resource.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
    error_messages = 'Current password ' + resource.errors[:current_password].join

    if resource.destroy_with_password(current_password)
      redirect_to '/'
    else
      redirect_to delete_account_path, notice: error_messages
    end
  end

  protected

  def configure_permitted_parameters
        devise_parameter_sanitizer.permit(:account_update) do |user_params|
      user_params.permit(:username, :email, :password, :password_confirmation, :current_password, :name, :phone_number
    end
  end

  private

  def password_required?
    (resource.email != params[:user][:email] if params[:user][:email].present?) || params[:user][:password].present?
  end
end

Обновить config/routes.rb:

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

В представлениях/разработке/регистрации/edit.html.haml

# edit form
...
= simple_nested_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: 'mo-form' }, defaults: { placeholder: false, hint: false }) do |f|
...

# delete form
...
= simple_form_for(resource, as: resource_name, url: user_registration_path(resource_name), method: :delete, html: { class: 'mo-form' }, defaults: { placeholder: false, hint: false }) do |f|
...