Rails 更新用户信息的时候取消对于密码的验证

woaigithub · 2012年11月13日 · 最后由 crazyjin 回复于 2013年04月22日 · 4865 次阅读

更新用户信息的时候取消对于密码的验证

假设有下面的 model

class User < ActiveRecord::Base
  attr_accessible :username, :email, :password

  validates :password, :presence => true
end

validates 用来在注册的时候验证密码。

但是用户修改个人信息的时候,我们一般不同时修改密码,用户可以修改密码意外的其他字段,修改页面也没有密码字段。 修改密码是另外独立的一个功能。

@user=User.find(params[:id])

@user.update_attributes(params[:user])

会验证所有的 validates,所以会提示密码不能为空。但是这时候我们不想出现这个提示。

下面这段代码只会更新 email 和 username

@user=User.find(params[:id])
    @user.email=params[:user][:email]
    @user.username=params[:user][:username]
    if @user.update_attribute(:username, params[:user][:username])
      flash[:notice]="update user successful"
      redirect_to @user
    else
      flash.now[:notice]="update user fail"
      render :edit
    end

但是也有遗憾,update_attribute 会 skip_validate,也就是说验证不起作用了,不知道大家碰到这个问题有没有好的解决办法。

devise 里面有一个方法 update_without_password(params[:user]) 可以在更新的时候跳过 password 字段。

参考文档:

How To: Allow users to edit their account without providing a password

https://github.com/plataformatec/devise/wiki/How-To%3a-Allow-users-to-edit-their-account-without-providing-a-password

http://stackoverflow.com/questions/7083575/updating-user-attributes-without-requiring-password

def update_without_password(params, *options)
        params.delete(:password)
        params.delete(:password_confirmation)

        result = update_attributes(params, *options)
        clean_up_passwords
        result
      end

这个代码很简单的,就是 delete,然后调用 update_attributes,可是我自己也是这么做的,还是会 validates,会报错 password 问题。 请问有哪位遇到过的,如何解决呢?

require 'digest'

class User < ActiveRecord::Base

  attr_accessor :password, :password_confirmation

  attr_accessible :username, :email, :password, :password_confirmation

#  has_secure_password

  validates :username, :presence => true, :length => { :in =>6..20 }, :uniqueness => true
  validates :email, :presence => true, :uniqueness => true
  validates :password, :confirmation => true, :presence => true
  validates :password_confirmation, :presence => true

  has_many :topics
  has_many :comments


  before_save :encrypt_password, :if => :password_changed?

  def authenticate(password)
    self.password_digest==Digest::SHA1::hexdigest(password)

  end


  def password_changed?
    !@password.blank?

  end

  private

  def encrypt_password
    self.password_digest=Digest::SHA1::hexdigest(self.password)
  end

end
def update
    @user=User.find(params[:id])

    @user.email=params[:user][:email]
    @user.username=params[:user][:username]
    if @user.update_attribute(:username, params[:user][:username])


      flash[:notice]="-update user successful"
      redirect_to @user
    else
      flash.now[:notice]="-update user fail"
      render :edit
    end

  end

下面这个就会验证 password,就算加上 delete(:password) 也没有用。

def update
    @user=User.find(params[:id])


    params[:user].delete(:password)
    params[:user].delete(:password_confirmatin)
    if @user.update_attributes(params[:user]) 


      flash[:notice]="-update user successful"
      redirect_to @user
    else
      flash.now[:notice]="-update user fail"
      render :edit
    end

  end

我想出来几个办法。 1.在 validates 后面加上个:if => Proc.new { |u| u.new_record? },然后修改密码,自己写 sql 执行。 2.更新用户和修改密码都自己写 sql 执行,还可以控制的很好。

当然了,还有第三个,直接使用第三方的 authentication,例如 devise

第一个办法,我刚才试验过了,行得通。

#1 楼 @woaigithub 代码整理一下吧

#8 楼 @huacnlee 谢谢帮忙整理,对了,如何搞多行代码呢?

class Topic < ActiveRecord::Base

end

学会了,在帮助里面学会了,谢谢!

我没做啥过多处理,就如下做了:

form_data.delete(:password) if form_data['password'].blank? form_data.delete(:password_confirmation) if form_data['password_confirmation'].blank? result = @user.update_attributes form_data

#11 楼 @pzgz o 你的 user 有验证码,对于密码有验证码?我的这里怎么就提示验证信息了呢?比如说长度,必填等等验证。

#12 楼 @woaigithub

嗯,有验证的,我的做法是,在保存的时候,如果表单里面带过来的密码和验证都是空的,那么我就从 hash 里面删除这两个节点,这样 model 上密码就不会被更改,保存的时候验证也就不会发生

你是说你的表单里面有密码和验证这两个 field,只是隐藏起来了,然后在 controller 中删除这两个 hash,然后不会发生验证。

#14 楼 @woaigithub

不隐藏,只是我这么认为用户的行为,如果用户没有在密码和密码验证两个字段中输入东西,那么我就认为他没有想要更改密码,这样我就把这两个字段的内容从表单的 hash 中删除,如果用户在这两个字段里面输入任何东西,这两个字段就不会被从哈希中删除,这样后台验证就会进行了

#15 楼 @pzgz 这样啊,可是一般修改信息和修改密码都是分开的,我比较不喜欢那种放在一起的,让我不知道我的密码是否需要再次输入,还是说不输入就不修改,还是说不输入会修改成空白密码,有点混乱吧。 我的界面上面只有其他信息,html 的 form 中没有 password 字段,所以在 params 中就没有 password 和 password_comfirmation。

嗯,如果分开的话那应该更好处理嘛,只要 html 中没有 password 的字段,后台的验证也应该不会在更改用户信息的时候发生的

#17 楼 @pzgz 验证发生了,所以我才想出这个办法的。

估计是我哪里写的有问题,我再找找看吧。

#18 楼 @woaigithub

嗯,估计你是隐藏了 html 字段,但是字段还是在,如果在表单上压根儿就没有那两个字段的话,就不会有问题了

刚才搞个 demo 验证了一下,在 controller 中 params[:user].delete(:password) 然后调用 @user.update_attributes(params[:user]) 就不会发生验证了。 Html 中是否包含 password_field 都没有问题。

我的表单是自己用 html 写的,没有 password 和 password_confirmation 字段 upate_attributes(params[:user]) 依然要验证 password 和 password_confirmation。 Rails 3.2.11

crazyjin update_attributes 方法更新部分属性问题 提及了此话题。 04月03日 10:56
需要 登录 后方可回复, 如果你还没有账号请 注册新账号