Разработать обновление пользователя без пароля


Я хочу обновить атрибуты пользователей без пароля в devise. Дело в том, что если поля пароля и подтверждения пароля не пусты, то мне нужно придумать ошибку, и если они пусты, то другие атрибуты пользователя должны быть обновлены. Как я мог сделать это с помощью devise?

спасибо заранее!

13 69

13 ответов:

Это то, что вы ищите? Из проекта Wiki

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

Он показывает, как это сделать для рельсов 3 и рельсов 4

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

Джон более простой вариант

Я думаю, что это гораздо лучшее решение:

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

поэтому, если пользователь является новым, он должен будет указать пароль. Однако пользователь exist должен будет указать пароль только в том случае, если он заполнит атрибуты 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 присутствует, вы можете продолжить и обновить пароль, иначе проигнорируйте его и обновите без пароля.

Если вы хотите придумать, чтобы проверить текущий пароль только тогда, когда пользователь пытается изменить пароль (это означает, что вы можете изменить другие атрибуты, без указания текущего пароля):

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'}

на маршруты.РБ.

Это больше бизнес-логики, так что я бы не положить слишком много кода в контроллер. Я предлагаю переопределить 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

как обходной путь положить в вашей модели пользователя

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

Я нахожу это небольшое изменение кода выше легче следовать:

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

после долгих исследований вышеуказанных возможностей я, наконец, нашел решение, которое позволяет обновлять некоторые атрибуты без пароля, а некоторые с:

Я сделал вид для пользователей/редактирования.формат 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 %>

я поставил стороны в стороны.РБ

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

Я сделал редактировать и обновлять методы в users_controller.РБ

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)

Я также установил параметры так, что электронная почта и пароль не могут быть изменены здесь. Чтобы обновить пароль и электронную почту, я ссылаюсь на созданный на складе devise view:

edit_user_registration_path(current_user)

Я признаю, что это огромная работа, но ни одно из более простых решений не решило все вышеперечисленные проблемы.