更新“用户”属性而不需要密码



现在,用户可以编辑他们的一些属性而不必输入他们的密码,因为我的验证是这样设置的:

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 

但出于某种原因,这是做同样的事情。如何在不更改密码的情况下更新某些用户属性?谢谢!

我没有意识到我昨天给你的解决方案会导致这个问题。对不起。

那么,从设计中获得灵感,你应该这样简单地更新你的控制器:

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解决方案放在这里。

到目前为止,我所看到的答案都不符合我的用例,它们似乎都以某种方式绕过验证,但我希望能够验证其他字段和密码(如果存在)。我也没有在我的项目中使用设计,所以我不能使用任何特别的东西。

值得指出的是,这是一个两部分的问题:

步骤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

2017答:

Rails 5中,正如Michael Hartl的教程所指出的,在你的模型中沿着这些行得到一些东西就足够了:

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

allow_nil: true是这里的关键。这允许用户编辑他/她的信息,而不需要修改密码。

在这一点上,人们可能会认为这也将允许空用户注册;然而,这可以通过使用has_secure_password来防止,CC_1会在create方法中自动验证密码是否存在。

这是一个用于说明目的的演示User模型:

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-zd-.]+.[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

不幸的是,我不知道如何使这个工作在设计。🖖欢呼声。

我有同样的问题,上面的解决方案对我不起作用。我发现了真正的罪魁祸首:我在我的User模型中有一个encrypt_password回调,它每次都将密码设置为空白。

before_save: encrypt_password

我通过在这个回调的末尾添加一个条件来修复它:

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

正确答案不再适用于rails 4。我相信我的答案是最干净和最通用的,它将在您想要省略任何属性(不仅仅是密码)时工作。如果您想要在许多不同的地方更新任何模型的单独属性,则需要这种方法。

例如,如果您想做Stack Overflow所做的事情,并通过security页面更新密码,通过用户显示视图更新配置文件图像,并通过用户编辑视图更新用户的大部分信息。

1)用一个类方法扩展hash class来删除空白值。我们将使用此方法删除未更新但仍存在于参数散列中的空白值:

1a)lib目录下创建一个hash.rb文件:

命令行

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

1b)hash.rb内部,'创建'一个Hash类并创建一个.delete_blanks!方法:

/lib/ext hash.rb

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

1c)要求这个文件(和你的整个lib目录)到rails中在初始化器中引用它:

配置/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)在users#update操作中,实现我们闪亮的新delete_blanks!类方法从参数哈希中删除我们不更新的属性。然后,通过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!方法将从参数散列中删除该属性,因此不会运行例如密码的验证。同样值得注意的是,delete_blanks!只删除值为nil的哈希条目,而不删除包含空字符串的哈希条目。因此,如果有人在用户创建表单(或任何有密码字段的表单)上遗漏了密码,则存在验证将生效,因为散列的:password条目不会为nil,它将是一个空字符串:

3a)在所有验证中使用if:选项:

应用程序/模型/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)

@user.username=params[:username]
if @user.update_attribute(:email,params[:email])
  flash[:notice]="successful"
else
  flash[:notice]="fail"
end

以上代码可以更新用户名和电子邮件字段。因为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

这显然是一个完全的黑客,但这是唯一的方法,我可以弄清楚它没有搞乱验证和删除密码!

相关内容

  • 没有找到相关文章

最新更新