Обновление атрибутов "Пользователь" без необходимости ввода пароля
Теперь пользователи могут редактировать некоторые свои атрибуты, не вводя их пароль, потому что мои проверки настроены следующим образом:
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
Но по какой-то причине это делает то же самое. Как я могу обновить некоторые пользовательские атрибуты без изменения пароля? Спасибо!
Ответы
Ответ 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 пропустит проверку.