我设置了一个User AR模型,它具有条件验证,与条件验证的Railscast episode几乎完全相同。所以基本上我的用户模型看起来像这样:
class User < ActiveRecord::Base
attr_accessor :password, :updating_password
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 },
:if => :should_validate_password?
def should_validate_password?
updating_password || new_record?
end
end
现在,在用户可以更改密码的操作中,我有以下两行:
@user.updating_password = true
if @user.update_attributes(params[:user]) ...
以便我标记要在密码上运行的验证。在开发模式下,这很有效 - 如果用户试图输入太短或太长的密码,则模型不会通过验证。我的问题是,对于我的生活,我无法通过我的测试。这是我的规范:
require 'spec_helper'
describe PasswordsController do
render_views
before(:each) do
@user = Factory(:user)
end
describe "PUT 'update'" do
describe "validations" do
before(:each) do
test_sign_in(@user)
end
it "should reject short passwords" do
short = "short"
old_password = @user.password
@attr2 = { :password => short, :password_confirmation => short }
put :update, :user_id => @user, :old_password => @user.password, :user => @attr2
@user.password.should == old_password
end
it "should reject long passwords" do
long = "a" * 41
old_password = @user.password
@attr2 = { :password => long, :password_confirmation => long }
put :update, :user_id => @user, :old_password => @user.password, :user => @attr2
@user.password.should == old_password
end
end
end
end
当我运行这些测试时,我总是收到错误:
1) PasswordsController PUT 'update' validations should reject short passwords
Failure/Error: @user.password.should == old_password2
expected: "foobar"
got: "short" (using ==)
当然密码错误太长了。但是,如果我在控制器中进行任何保存尝试之前设置@user.updating_password = true
,是否应该验证密码?
答案 0 :(得分:1)
我认为问题不是代码,而是你期望它做的事情。当您调用update_attributes并传入错误值时,即使验证失败,该值也会保存到模型对象中;坏值尚未推送到数据库。
我认为这是有道理的,因为当验证失败时,你会再次使用错误消息显示表单,输入填充传入的错误值。在Rails应用程序中,这些值通常来自模型对象有问题。如果错误值未保存到模型中,则它们将丢失,并且您的表单将表明旧的“良好”值未通过验证。
而不是执行此检查:
@user.password.should == old_password
也许试试:
@user.errors[:password].should_not == nil
或其他一些有意义的测试。