2010-07-17 48 views
7

所以我有一个用户模型,包括登录名,电子邮件地址,密码,密码确认,名称,头像(图片)等。前5个验证,基本上说明所有5个都需要存在才能创建一个新模型。Rails - update_attributes来验证

但是,这对我来说更新有关问题。

我有一个编辑页面,用户只能编辑他们的名字和头像。我目前不打算让他们更改他们的登录名,我希望从其他页面更改电子邮件和密码。

所以编辑形式如下:

<% form_for @user, :html => { :multipart => true } do |u| %> 
<p> 
    <label>Name:</label> 
    <%= u.text_field :name %> 
</p> 
<p> 
    <label>Avatar:</label> 
    <%= display_user_avatar %> 
    <%= u.file_field :avatar%> 
</p> 
<p> 
    <%= submit_tag %> 
</p> 
<% end %> 

如果我试图做一个@user.update_attributes(params[:user]),则因为只有2个PARAMS是nameavatar,更新失败,因为东西像密码,确认密码,电子邮件等是必需的,以验证条目,他们根本不存在这种形式。

我可以通过做@user.update_attribute(:name, params[:user][:name])来解决这个问题,但是我担心避免验证是否是一件好事?尤其是关于密码更新等问题,我需要验证新密码。

还有别的办法吗?

如果我做到这一点简单地使用update_attribute为:name:avatar,我怎么会去这样做呢?

会这样吗?

params[:user].each do |attribute| 
    @user.update_attribute(attribute, params[:user][attribute]) 
end 

这是一个可接受的方式来做到这一点...?


--edit作为跟进 -
Okie,我想如你所说,做

所以它做的!版本,异常夹在浏览器中显示&是:

Validation failed: Password is too short (minimum is 5 characters) 

服务器日志中的信息是:

Processing UsersController#update (for 127.0.0.1 at 2010-07-18 11:56:59) [PUT] 
    Parameters: {"user"=>{"name"=>"testeeeeee"}, "commit"=>"Save changes", "action"=>"update", "_method"=>"put", "authenticity_token"=>"BMEGRW/pmIJVs1zlVH2TtZX2TQW8soeCXmMx4kquzMA=", "id"=>"tester", "controller"=>"users"} 

Urm。看着这个,我刚刚意识到它正在提交"id"=>"tester"。现在,我设置了路由,以便显示用户登录名,而不是user_id ...可能是为什么?它试图找到user_id == tester用户的更新,但由于它不存在,它会尝试创建一个? 实际上是由于路线我做错了吗?

嗯......耙路线告诉我的路线是:

edit_user GET /users/:id/edit(.:format)        {:action=>"edit", :controller=>"users"} 
      PUT /users/:id(.:format)         {:action=>"update", :controller=>"users"} 

我设置了这样的路线在user.rb文件:

def to_param 
    "#{login}" 
    end 

,但它肯定被显示的login代替id这么长的时间。但是在更新操作开始时我也正确地做了一个@user = User.find_by_login(params[:id]),然后更新@user

我很困惑。 >。 <


二更新:

User.rb验证的东西如下:

validates_length_of :login, :within => 3..20 
    validates_length_of :password, :within => 5..20 
    validates_presence_of :login, :email, :password, :password_confirmation, :salt, :name, :on => :create 
    validates_uniqueness_of :login, :case_sensitive => false 
    validates_confirmation_of :password 
    validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :message => "format is invalid." 
    attr_accessor :password, :password_confirmation 

而且hashed_pa​​ssword部分是在这里:

def password=(pass) 
    @password = pass 
    self.salt = User.random_string(10) if !self.salt? 
    self.hashed_password = User.encrypt(@password, self.salt) 
    end 

u.attributes给我

>> u.attributes 
=> {"salt"=>"NHpH5glxsU", "name"=>"test er", "avatar_updated_at"=>nil, "updated_at"=>Sat Jul 17 07:04:24 UTC 2010, "avatar_file_size"=>nil, "avatar_file_name"=>nil, "hashed_password"=>"84f8675c1ed43ef7f8645a375ea9f867c9a25c83", "id"=>1, "avatar_content_type"=>nil, "login"=>"tester", "email"=>"[email protected]", "created_at"=>Fri May 07 10:09:37 UTC 2010} 

Urmmm ......好了,这是你说的,关于虚拟属性password是不存在的实际... 那么,如何避开? Bugger,在这里我认为我正在用我自己的验证代码摆弄...

更改为其中一个身份验证插件有多简单?我需要创建一个新的用户模型吗?还是应该插件能够使用我现有的插件?

感谢所有帮助到目前为止,btw! :D

+0

PS:是的,'

+0

你描述的内容对我来说听起来不太合适,我敢肯定,如果你使用'Hash'做'update_attributes'只包含一部分属性,那么所有其他的属性都保留下来他们之前的值意味着验证不应该失败 – mikej 2010-07-17 15:53:48

回答

10

我已经检查了这一点,并通过update_attributes工作正常只是2属性的部分更新。所有其他属性都保留有以前的值,这意味着验证不应该失败。有几件事可以尝试:

  • 在您的控制器操作中,您是否通过User.find加载用户?即你是从一个有效的模型开始的。
  • 您确定由于验证错误而导致更新失败吗?尝试用update_attributes!替换update_attributes。如果更新由于验证而失败,后者将抛出异常。或在尝试更新后检查@user.errors以确认哪个验证失败。

更新

如果User.find_by_login没有找到匹配的记录,将返回nil并不会为你创建一个新的记录。数据库中的测试人员用户有可能是否有太短的密码?也许该用户是在将验证放入代码之前创建的?在保存记录之前,您是否使用任何类型的插件或回调来加密用户密码?password实际上是一个未保存的虚拟属性,而实际的密码位于encrypted_password之类的字段中?

script/console试试这个(使用你正在测试与应用程序相同的环境 - 开发或生产)

> user = User.find_by_login 'tester' 
> user.valid? 
> user.attributes 

user.valid?将返回falsetrue并会告诉你用户是否有效启动与之前,你甚至尝试更新。

更新2(固定验证)

在修复自己的代码方面,你可以添加一个方法类似下面你User型号:

def password_validation_required? 
    hashed_password.blank? || [email protected]? 
end 

,然后更新所有与密码相关的验证规则,以便它们仅适用于此方法返回true例如

validates_length_of :password, :within => 5..20, 
    :if => :password_validation_required? 

这是什么要说的是只能做密码验证规则,如果我们还没有一个hashed_password(上例如新用户),或是否有新的明文密码已经通过password=规定。如果用户已经有密码并且保持不变,则跳过密码验证。

虽然你是正确的考虑使用插件。编写自己的身份验证代码可能是一项有趣的练习,如果您有一些不寻常的要求,则可能需要这样做。不好的一面是可能存在你没有想到的安全问题。改装类似restful_authentication到你的应用程序不应该太糟糕。您可能只需要重命名User型号的一个或两个字段。

+0

Okie,我刚刚更新了原来的帖子和我尝试过的结果,哦,当我刚做'update_attributes'时,闪烁显示'@users。错误',我在闪存中有一个'#',就是这样,这让我想知道它是否是'id = tester'更新的问题... – 2010-07-18 02:11:59

+0

@ Jty.tan答案更新了一些建议,让我知道他们是否有任何帮助 – mikej 2010-07-18 09:32:43

+0

哦,你是对的...我做了一个'u.valid?',并得到了一个'虚假'的回报 嗯......我只是试着用最新的用户我创建了(成功的),并且我还得到了'有效?'的虚假回报...... 因此,它与我的用户模型和验证有关?是的,我的用户密码是加密的,并且加密的密码是保存的密码... 我将再次用我的user.rb中的验证更新。 – 2010-07-18 13:39:27