Rails中的补丁方法如何仅更新某些属性而其他属性为空?

时间:2015-05-22 13:02:08

标签: ruby-on-rails ruby validation patch updatemodel

我在阅读Ruby On Rails教程时遇到了这些问题 here

User类的验证是:

class User < ActiveRecord::Base
   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, length: { minimum: 6 }, allow_blank: true
   .
   .
   .
end

在测试中,将更新的用户信息修补到用户的路线,如下所示:

def setup
  @user = users(:michael)
end
.
.
.
test "successful edit" do
  get edit_user_path(@user)
  assert_template 'users/edit'
  name  = "Foo Bar"
  email = "foo@bar.com"
  patch user_path(@user), user: { name:  name,
                                email: email,
                                password:              "",
                                password_confirmation: "" }
  assert_not flash.empty?
  assert_redirected_to @user
  @user.reload
  assert_equal name,  @user.name
  email, @user.email
end

测试将通过,只会更新用户的姓名和电子邮件,密码不会更改。

如果密码验证不包含“allow_blank:true”,则此测试将失败。

所以我不明白:当测试通过时意味着密码可能为空,为什么它不会将密码更改为空白? Rails怎么知道我只想更新一些属性?

1 个答案:

答案 0 :(得分:2)

has_secure_password为您的模型添加password= setter method方法,在设置密码时会丢弃empty?输入。

irb(main):012:0> "".empty?
=> true

这可以防止用户选择空白密码。如果你不想接受我的话,你可以很容易地测试一下:

test "does not change password to empty string" do
  patch user_path(@user), user: { name:  name,
                                  email: email,
                                  password:              "",
                                  password_confirmation: "" }
  @user.reload
  assert_false @user.authenticate("")
end

但是,验证确实做的是,如果用户设置密码,则必须超过6个字符:

test "does not allow a password less than 6 characters" do
  patch user_path(@user), user: { name:  name,
                                  email: email,
                                  password:              "abc",
                                  password_confirmation: "abc" }
  assert assigns(:user).errors.key?(:password)
end

(PS。这是在模型测试中比在控制器测试中更好的测试)