Обновление атрибутов "User" без пароля
прямо сейчас пользователи могут редактировать некоторые свои атрибуты без ввода пароля, потому что мои проверки настроены следующим образом:
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
но по какой-то причине это делает то же самое вещь. Как я могу обновить некоторые атрибуты пользователя без изменения пароля? Спасибо!
9 ответов
Ну, черпая вдохновение от devise, вы должны просто обновить контроллер таким образом:
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
этот блог демонстрирует основные того, что вы хотите сделать.
что не показано, но может быть полезно, это добавить аксессоры к модели:
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?
!@new_password.blank? or encrypted_password.blank?
end
я боролся с этим и ходил по кругу какое-то время, поэтому я думал, что поставлю свое решение Rails 4 здесь.
ни один из ответов, которые я видел до сих пор, не соответствует моему варианту использования, все они, похоже, каким-то образом обходят проверку, но я хочу иметь возможность проверять другие поля, а также пароль (если есть). Также я не использую devise в своем проекте, поэтому я не могу использовать что-то конкретное.
стоит отметить, что это 2 часть проблема:
Шаг 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-пропустить проверку, если пароль не установлен.
# 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
У меня была такая же проблема, и решения не работает для меня. Я нашел реального виновника в моем случае: у меня был обратный вызов encrypt_password в моей пользовательской модели, которая каждый раз устанавливала пароль пустым.
before_save: encrypt_password
я исправил это, добавив условие в конце для этого обратного вызова:
before_save: encrypt_password,: если только => Proc.новый { |u| u.пароль.пустой? }
2017 ответ:
на рельсы 5 Как также указано Майклом Хартлом учебник, достаточно того, что у вас есть что-то в этом роде в вашей модели:
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+\-.]+@[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
Я понятия не имею, как это сделать с разработки. Мои два цента.
правильный ответ больше не работает для rails 4. Я считаю, что мой ответ самый чистый и самая универсальная это будет работать, когда вы хотите оставить любой атрибуты (не только пароль). Этот подход будет необходим, если вы хотите обновить отдельные атрибуты любой модели в различных местах.
например, если вы хотите сделать то, что делает переполнение стека, и иметь пароли, обновляемые через security
страница, изображение профиля updatable через пользователя показать вид и масса информации пользователя updatable через представление редактирования пользователей.
1) продлить hash class
С помощью метода класса для удаления пустых значений. Мы будем использовать этот метод для удаления пустых значений, которые не обновляются, но все еще присутствуют в хэше params:
1А) создать в своем , под ext
каталог:
командная строка
$ mkdir lib/ext
$ touch lib/ext/hash.rb
1b) внутри hash.rb
, 'create' a Hash
класс и создать .delete_blanks!
способ:
lib/ext / hash.rb
class Hash
def delete_blanks!
delete_if { |k, v| v.nil? }
end
end
1С) требовать этот файл (и весь ваш каталог 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) внутри пользователи#обновить действие, реализовать наши блестящие новые delete_blanks! метод класса для удаления атрибутов, которые мы не обновляем из хэша params. Затем обновите экземпляр пользователя с помощью update_attributes
метод, *не update
способ!
2а) во-первых, давайте использовать delete_blanks! метод исправления нашего хэша user_params:
app / контроллеры / users_controller.rb
new_params = user_params.delete_blanks!
2b) а теперь давайте обновим экземпляр, использующий update_attributes
метод (опять же, не update
способ):
app / контроллеры / users_controller.rb
@user.update_attributes(new_params)
вот как закончил users#update
действие:
app / контроллеры / 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. Наши!--22--> метод удалит атрибут из хэша params, поэтому проверка пароля, например, не будет запущена. Также стоит отметить, что delete_blanks!
удаляет только хэш-записи со значением Нил, а не с пустыми строками. Поэтому, если кто-то оставляет пароль в форме создания пользователя (или любой форме с полем для пароля), проверка присутствия вступит в силу, потому что: ввод пароля хэша не будет nil, это будет пустая строка:
3a) использовать if:
опция для всех проверок:
app / модели / пользователь.rb
VALID_EMAIL_REGEX = /[a-zA-Z0-9_.+-]+@[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
экземпляры, на бесконечном количестве различных моделей. Просто помните, когда вы хотите сделать это с новой моделью, вам нужно повторить шаги 2а), 2b) и 3a)
@user.username=params[:username]
if @user.update_attribute(:email,params[:email])
flash[:notice]="successful"
else
flash[:notice]="fail"
end
выше код можно обновить имя пользователя и поле email. потому что update_attribute может обновлять грязные поля. но жаль, update_attribute пропустит проверку.
у меня была та же проблема. Я не смог исправить это с помощью
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
который явно полный хак, но его единственный способ, которым я могу понять это, не возясь с проверками и удалением пароля!