Обновление атрибутов пользователя без пароля - PullRequest
26 голосов
/ 16 августа 2011

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

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 ]

22 голосов
/ 17 августа 2011

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

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

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
12 голосов
/ 19 марта 2012

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

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

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, чтобы определить, изменился ли пароль? для запроса пароля на новую запись.

  def password_changed?
    !@new_password.blank? or encrypted_password.blank?
  end
10 голосов
/ 22 ноября 2013

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

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

Стоит отметить, что проблема состоит из двух частей:

Шаг 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 - пропустить проверку, если пароль не установлен.

5 голосов
/ 27 июня 2012
# 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
4 голосов
/ 09 января 2012

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

before_save: encrypt_password

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

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

3 голосов
/ 26 июля 2017

2017 ответ:

В Rails 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

Понятия не имею, как это сделать с помощью устройства. Мои два цента.

2 голосов
/ 07 апреля 2014

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

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

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

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

командная строка

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

1b) Внутри hash.rb, «создать» aHash Класс и создать .delete_blanks! метод:

lib / ext / hash.rb

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

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

config / 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) Внутриuser # update action, реализуйте наши новые блестящие delete_blanks!Метод класса для удаления атрибутов, которые мы не обновляем из хэша params.Затем обновите пользовательский экземпляр с помощью метода update_attributes, * не метода update!

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

app / controllers / users_controller.rb

new_params = user_params.delete_blanks!

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

app / controllers / users_controller.rb

@user.update_attributes(new_params)

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

app / controllers / 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: для всех проверок:

app / models / user.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 на бесконечном количестве различных моделей.Просто помните, когда вы хотите сделать это с новой моделью, вам нужно повторить шаги 2a) , 2b) и 3a)

0 голосов
/ 13 ноября 2012
@user.username=params[:username]
if @user.update_attribute(:email,params[:email])

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

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

0 голосов
/ 17 августа 2011

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

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

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

...