Обновление атрибутов "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

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