Подтвердить что ты не робот

Обновление атрибутов "Пользователь" без необходимости ввода пароля

Теперь пользователи могут редактировать некоторые свои атрибуты, не вводя их пароль, потому что мои проверки настроены следующим образом:

validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? } 

Однако после того, как пользователь сделает это, их пароль будет удален - update_attributes обновляет свой пароль до "". Вот мое определение для обновления:

def update

    if @user.update_attributes(params[:user])
        flash[:success] = "Edit Successful."
        redirect_to @user
    else
        @title = "Edit user"
        render 'edit'
    end
end

Я также попытался использовать другое определение, которое вместо этого использует update_attribute:

def save_ff
    @user = User.find(params[:id])
    @user.update_attribute(:course1, params[:user][:course1] )
    @user.update_attribute(:course2, params[:user][:course2] )
    @user.update_attribute(:course3, params[:user][:course3] )
    @user.update_attribute(:course4, params[:user][:course4] )
    redirect_to @user 
end 

Но по какой-то причине это делает то же самое. Как я могу обновить некоторые пользовательские атрибуты без изменения пароля? Спасибо!

4b9b3361

Ответ 1

Я не понимал, что решение, которое я вам дал вчера, приведет к этой проблеме. К сожалению.

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

def update
  params[:user].delete(:password) if params[:user][:password].blank?
  if @user.update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end

Ответ 2

Это сообщение в блоге демонстрирует принцип того, что вы хотите сделать.

Что не показано, но может быть полезно, заключается в добавлении аксессуаров к модели:

attr_accessor   :new_password, :new_password_confirmation
attr_accessible :email, :new_password, :new_password_confirmation

и предоставить всю необходимую проверку при условии, что пользователь предоставил новый пароль.

  validates :new_password,  :presence => true, 
                            :length   => { :within => 6..40 }, 
                            :confirmation => true, 
                            :if       => :password_changed?

Наконец, я бы добавил проверку, чтобы проверить, был ли установлен encrypted_password, чтобы определить, "password_changed?" чтобы потребовать пароль для новой записи.

  def password_changed?
    [email protected]_password.blank? or encrypted_password.blank?
  end

Ответ 3

Я боролся с этим и немного крутился по кругу, поэтому я подумал, что поставлю решение Rails 4 здесь.

Ни один из ответов, которые я видел до сих пор, не соответствует моему варианту использования, все они, похоже, в какой-то мере обходят проверку, но я хочу, чтобы иметь возможность проверять другие поля, а также пароль (если он есть). Кроме того, я не использую проект в своем проекте, поэтому я не могу использовать что-то особенное.

Стоит отметить, что это проблема с двумя частями:

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

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

Шаг 2 - вам нужно изменить валидацию, чтобы пароль не был проверен, если он не был введен. Мы не хотим, чтобы оно было пустым, поэтому почему мы удалили его из наших параметров раньше.

В моем случае это означает, что это как подтверждение в моей модели:

validates :password, :presence => true, :confirmation => true, length: {minimum: 7}, :if => :password

Обратите внимание: if = > : password - пропустить проверку, если пароль не установлен.

Ответ 4

# It smells

def update
  if params[:user][:password].blank?
    params[:user].delete :password
    params[:user].delete :password_confirmation
  end

  if @user.update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end

# Refactoring

class User < ActiveRecord::Base
  ...
  def update_attributes(params)
    if params[:password].blank?
      params.delete :password
      params.delete :password_confirmation
      super params
    end
  end
  ...
end

def update
  if @user.update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end

# And little better

class User < ActiveRecord::Base
  ...
  def custom_update_attributes(params)
    if params[:password].blank?
      params.delete :password
      params.delete :password_confirmation
      update_attributes params
    end
  end
  ...
end

def update
  if @user.custom_update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end

Ответ 5

У меня была такая же проблема, и решения выше не работали для меня. Я нашел настоящего виновника в моем случае: у меня был обратный вызов encrypt_password в моей модели User, который каждый раз задавал пароль.

before_save: encrypt_password

Я исправил это, добавив условие в конец для этого обратного вызова:

before_save: encrypt_password,: if = > Proc.new {| u | u.password.blank? }

Ответ 6

Правильный ответ больше не работает для рельсов 4. Я считаю, что мой ответ - самый чистый и самый универсальный, который будет работать, когда вы захотите оставить любые атрибуты (а не только пароль). Этот подход понадобится, если вы хотите обновить отдельные атрибуты любой модели в разных местах.

Например, если вы хотите делать то, что делает Stack Overflow, и обновлять пароли с помощью страницы security, изображение профиля, обновляемое через представление пользователя, и основную часть информации пользователя, обновляемую через представление редактирования пользователя.

1) Расширьте hash class методом класса, чтобы удалить пустые значения. Мы будем использовать этот метод для удаления пустых значений, которые не обновляются, но все еще присутствуют в хеше params:

1a) Создайте файл hash.rb в каталоге lib в каталоге ext:

командной строки

$ mkdir lib/ext
$ touch lib/ext/hash.rb 

1b) Внутри hash.rb, 'create' a Hash и создайте метод .delete_blanks!:

Библиотека/внутр/hash.rb

class Hash
    def delete_blanks!
        delete_if { |k, v| v.nil? }
    end
end

1c) Требовать этот файл (и весь каталог lib) в рельсы, ссылающиеся на него в инициализаторе:

конфигурации /boot.rb

# other things such as gemfiles are required here, left out for brevity

Dir['lib/**/*.rb'].each { |f| load(f) } # requires all .rb files in the lib directory 

2) Внутри действия # update для пользователей реализуйте наши блестящие новые delete_blanks! класса для удаления атрибутов, которые мы не обновляем из хэша params. Затем обновите экземпляр пользователя с помощью метода update_attributes, а не метода update!

2a) Во-первых, используйте delete_blanks! метод для исправления нашего хэша user_params:

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

new_params = user_params.delete_blanks!

2b) Теперь давайте обновим экземпляр, используя метод update_attributes (опять же, не метод update):

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

@user.update_attributes(new_params)

Вот как выглядит законченное действие users#update:

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

def update

    new_params = user_params.delete_blanks!

    if @user.update_attributes(new_params)
        redirect_to @user, notice: 'User was successfully updated.'
    else
        render action: 'edit' // or whatever you want to do
    end
end

3) В модели User добавьте параметр if: :<attribute> ко всем вашим проверкам. Это делается для того, чтобы проверка выполнялась только в том случае, если атрибут присутствует в хеше params. Наш метод delete_blanks! удалит атрибут из хэша params, поэтому проверка пароля, например, не будет запущена. Также стоит отметить, что delete_blanks! удаляет только записи хэша со значением nil, а не с пустыми строками. Поэтому, если кто-то оставляет пароль для пользователя, создающего форму (или любую форму с полем для пароля), проверка наличия вступает в силу, поскольку: пароль ввода хэша не будет равен нулю, это будет пустой строка:

3a) Используйте параметр if: для всех проверок:

приложение/модели/user.rb

VALID_EMAIL_REGEX = /[a-zA-Z0-9_.+-][email protected][a-zA-Z0-9-]+\.[a-zA-Z0-9\-.]/

validates :first_name, presence: true, if: :first_name
validates :last_name, presence: true, if: :last_name
validates :user_name, presence: true, if: :user_name

validates :email, presence: true, 
                  uniqueness: { case_sensitive: false },
                  format: { with: VALID_EMAIL_REGEX }, if: :email 

validates :password, length: { minimum: 6, maximum: 10 }, if: :password

И что это. Теперь модель пользователя может быть обновлена ​​во многих и разных формах по всему вашему приложению. Валидации присутствия для атрибута по-прежнему вступают в игру в любой форме, которая содержит поле для него, например. валидация присутствия пароля по-прежнему будет отображаться в представлении user#create.

Это может показаться более подробным, чем другие ответы, но я считаю, что это самый надежный способ. Вы можете обновлять по отдельности бесконечное количество атрибутов для экземпляров User на бесконечном количестве разных моделей. Просто помните, когда вы хотите сделать это с помощью новой модели, вам нужно повторить шаги 2a), 2b) и 3a)

Ответ 7

Это то, что работает для меня:

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

    validates :password, presence: true, 
                     length:{minimum: 6},
                     :if => :password
    #validates conditions for other attributes

Используйте update_attributes для обновления различных атрибутов с помощью проверки

  def update
     @user = User.find(params[:id])
     if [email protected]_attributes(user_params)
         render 'edit'
     else
         flash[:success] = "Modification saved!"
         redirect_to @user
     end
  end
  private
      def user_params
           params.require(:user).permit(:first_name, :last_name, :password, :password_confirmation)
      end

Когда вы смотрите на журнал сервера, вы можете увидеть, что update_attributes будет генерировать запрос sql update, который обновляет только измененные атрибуты. Следовательно, вам не нужно удалять пароль из параметров, если он равен нулю.

Ответ 8

2017 ответ:

В Rails 5, как также указано Майклом Хартлом tutorial, достаточно, чтобы у вас что-то было эти строки в вашей модели:

validates :password, presence: true, length: { minimum: 6 }, allow_nil: true

allow_nil: true - это ключ, который позволяет пользователю редактировать свою информацию без необходимости изменения пароля.

В этот момент можно подумать, что это также позволит пустые пользовательские регистрации; Однако это предотвращается с помощью has_secure_password, который автоматически проверяет наличие пароля, но только метод create.

Это демонстрационная модель пользователя для иллюстрации:

class User < ApplicationRecord
  attr_accessor :remember_token
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                format: { with: VALID_EMAIL_REGEX },
                uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
  .
  .
  .
end

Я не знаю, как это сделать с помощью. Мои два цента.

Ответ 9

У меня была такая же проблема. Я не смог его исправить с помощью

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

Мне только удалось заставить его работать, выполнив "update_attribute" для каждого элемента отдельно, например.

if (  @user.update_attribute(:name, params[:user][:name])     && 
      @user.update_attribute(:email, params[:user][:email])   &&
      @user.update_attribute(:avatar, params[:user][:avatar]) &&
      @user.update_attribute(:age, params[:user][:age])       && 
      @user.update_attribute(:location, params[:user][:location]) &&
      @user.update_attribute(:gender, params[:user][:gender]) && 
      @user.update_attribute(:blurb, params[:user][:blurb])   )        
    flash[:success] = "Edit Successful."
    redirect_to @user
else
  @title = "Edit user info"
  render 'edit'
end

который явно является полным взломом, но его единственным способом я могу понять это, не испортив валидацию и не удалив пароль!

Ответ 10

@user.username=params[:username]
if @user.update_attribute(:email,params[:email])

  flash[:notice]="successful"
else
  flash[:notice]="fail"
end

выше код может обновлять имя пользователя и адрес электронной почты. потому что update_attribute может обновлять грязные поля. но жаль, update_attribute пропустит проверку.