【问题标题】:How could patch method in Rails update only some attributes while the other attributes are blank?Rails 中的补丁方法如何仅更新某些属性而其他属性为空?
【发布时间】:2015-05-22 13:02:08
【问题描述】:

我在阅读 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 怎么会知道我只是想更新一些属性?

【问题讨论】:

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


【解决方案1】:

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。这是在模型测试中比在控制器测试中更好地测试的东西)

【讨论】:

  • 如果测试关闭,我深表歉意,我几乎只使用 RSpec 并在内存不足的情况下输入它们。
  • 另外作为旁注,您应该真正拆分您的测试。最佳实践是每次测试一个断言,并且在同一个示例中测试多个控制器方法是非常糟糕的测试的秘诀。如果您想通过应用程序测试用户路径,请使用 Capybara 之类的集成测试。
  • 你的意思是如果我添加“allow_blank:true”,空白密码会通过测试但由于has_secure_password不会存储到数据库中?
  • 有点,password= 设置器使得当您将参数分配给用户时,空白密码被过滤掉 - 所以空白密码意味着password == nil。 , allow_blank:true 告诉 rails 在密码为空或 nil 时忽略 length: { minimum: 6 } 验证。
  • has_active_password 只存储password_digest。如果密码为 nil,则 has_active_password 不会生成新的摘要 - 因此不会将新密码保存到数据库中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-01
  • 1970-01-01
  • 2020-11-14
相关资源
最近更新 更多