Придумайте користувача оновлення без пароля


78

Я хочу оновити атрибути користувачів без пароля у розробці. Справа в тому, що якщо поля та поля для підтвердження пароля не є порожніми, то мені потрібно розробити помилку, а якщо вони порожні, то інші атрибути користувача потрібно оновити. Як я міг це зробити за допомогою приладу?

Спасибі заздалегідь!

Відповіді:


64

Це те, що ви шукаєте? З вікі Devise

Дозволити користувачам редагувати свій обліковий запис без введення пароля

Це показує, як це зробити для рейок 3 і рейок 4

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

Рішення Джона - простіша альтернатива


1
З тих пір Хосе Валім видалив багато інформації з цієї вікі, щоб порадити користувачам писати власні контролери та не замінювати методи у успадкованих Devise::RegistrationsControllers. Можна подивитися історію вікі для попередніх версій, але враховуйте його поради.
Abe Voelker,

93

Я думаю, що це набагато краще рішення:

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дії, щоб встановити нові параметри з форми.


Ідеально Саме те, що я шукав
karlingen

4
куди ти це кладеш?
Олександр Пресбер

5
@MoMolog Дотримуйтесь першої частини підручника Devise : github.com/plataformatec/devise/wiki/ ... Просто створіть порожній контролер спеціальних реєстрацій. Після цього скопіюйте функцію оновлення на стандартний контролер реєстрації Devise звідси: github.com/plataformatec/devise/blob/master/app/controllers/... Помістіть код Джона у верхню частину контролера. Замінити "update_resource (resource, account_update_params)" на "@ user.update_attributes (account_update_params)"
onichase

Ви можете помістити це в модель? @onichase
ahnbizcad

4
Це рішення не розглядається current_password. Він призначений для випадку, коли на додаток до полів для зміни пароля відображаються всі атрибути користувача (ім'я, електронна пошта тощо) . Без такої логіки Devise не дозволить оновлювати будь-які атрибути, якщо користувач подає форму, змінивши інші поля, залишаючи поля пароля порожніми.
Джон

18

Я думаю, що з Devise 3.2+ ви можете просто перевизначити update_resource у своєму підкласичному контролері. Ось приклад запитання, яке спочатку задавали:

class MyRegistrationsController < Devise::RegistrationsController
  protected

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

Ця відповідь, яка править усіма, на сьогоднішній день найпростіша станом на 2015 рік.
Asciant

3
Просто переконайтесь і оновіть свої маршрути:devise_for :users, controllers: {registrations: 'registrations'}
Ділан Літл

Гаразд для мене, але мені також довелося додати attr_accessor :current_passwordдо своєї моделі користувача. Начебто хаки мені не подобаються. Повинен я?
masciugo

Ви можете просто додати params.delete :current_passwordранішеresource.update_without_password(params)
sebsonic2o

Це також офіційно задокументовано github.com/heartcombo/devise/wiki/…
woto

8

Я вирішив цю проблему наступним чином: якщо форма подається з паролем, то потрібно заповнити поле 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

1
Ця відповідь є найбільш повною, а рішення найкращим
Дієго Сомар,

4

params [: user] [: password] не працює на рейках 6

Ви повинні змінити параметри [: користувач] [: пароль] на параметри [: пароль]

Видалити [: user] у всіх параметрах

мій вихідний код нижче

перед запуском цієї команди

rails генерують пристрій: контролери користувачів -c = реєстрації

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

3

Я вирішую цю проблему за допомогою свого інтерфейсу. Існує два шляхи.

Вимкніть поля, якщо вони порожні

Цей біт 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();
});

У будь-якому випадку це не вимагає оновлення самого додатка. Ви просто подаєте поля, які хочете змінити.


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


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

Таким чином, якщо поточний_пароль присутній, ви можете продовжувати та оновлювати пароль, інакше ігнорувати його та оновлювати без пароля.


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

в маршрутах.рб .


1

Це більше бізнес-логіка, тому я не ставлю занадто багато коду в контролер. Я пропоную замінити Devise::Models::Validatable#password_required?у вашій моделі:

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

Це, безумовно, найкращий спосіб зробити це. Також найбільш настроюваний, оскільки можна точно вказати, для яких атрибутів потрібен пароль.
Вадим

1

Як обхідний шлях, закладений у вашу модель користувача

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

1

Для майбутніх співробітників Google я просто витратив на це 3 години, ось що мені вдалося.

У моїй користувацькій моделі я видаляю: перевіряється та додав перевіряє метод для пароля та підтвердження_пароля, лише якщо вони присутні:

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

Потім у методі оновлення користувача_контролера я видаляю параметри підтвердження пароля та пароля, якщо вони порожні

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.

Вас усіх вітаємо.


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

У маршрутах.rb:

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

Повна заслуга: Масатоші Нішігучі

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


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

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

0

Після довгих досліджень вищезазначених можливостей я нарешті знайшов рішення, яке дозволяє оновити деякі атрибути без пароля, а деякі за допомогою:

Я зробив подання для користувача / 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]

Я зробив методи редагування та оновлення в user_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)

Я визнаю, що це величезна робота навколо, але жодне з більш простих рішень не вирішило всіх вищезазначених проблем.


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

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

перший рядок перевіряє, "надсилає користувач правильний пароль чи ні", а потім ми можемо оновити атрибути без сміття

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.