简体   繁体   English

Michael Hartl Rails 教程:assert_not 与它应该做的完全相反,我不明白为什么

[英]Michael Hartl Rails tutorial: assert_not does exact opposite of what it should and I don't understand why

tl;dr Valid names don't get written to the database because the test fails, and invalid names do get written to the database because the test passes. tl;dr 有效名称不会因为测试失败而写入数据库,而无效名称会因为测试通过而写入数据库。

Edit: For clarification about the project and my question in general: As described in the book, this User model is set up as the beginning stages to allow a website user to eventually log in to a website.编辑:为了澄清项目和我的一般问题:如书中所述,此用户模型设置为开始阶段,以允许网站用户最终登录网站。 The database columns would be "name" and "email", and each row would be one user (assuming the user name and email were valid).数据库列将是“姓名”和“电子邮件”,每一行将是一个用户(假设用户名和电子邮件是有效的)。 I've edited my original post below for further clarification, and all edits are in italics.为了进一步说明,我在下面编辑了我的原始帖子,所有编辑都以斜体显示。

Additionally, please only respond if you can explain the code as is in my post--don't suggest adding additional code to make it work.此外,请仅在您能我的帖子中那样解释代码时才回复——不要建议添加额外的代码以使其工作。 The textbook I'm working from asserts that this code should work as is, yet it seems to evaluate to the opposite that it should.我正在工作的教科书断言这段代码应该按原样工作,但它的评估结果似乎与它应该相反。 Lastly, if you know other links that explain this in more detail, that is helpful;最后,如果您知道更详细地解释这一点的其他链接,那将很有帮助; however, I have already read apidock , RoR API , and most of the SO links that show up in a Google search, and none have been helpful in explicating this problem.但是,我已经阅读了apidockRoR API和大多数出现在 Google 搜索中的 SO 链接,但没有一个有助于解释这个问题。

I'm working through Michael Hartl's Ruby on Rails Tutorial.我正在学习 Michael Hartl 的 Ruby on Rails 教程。 I'm in chapter 6 working through validation tests and I'm stuck on the validation for the presence of a name.我在第 6 章进行验证测试,但我一直在验证名称是否存在。 It seems to be doing exactly the opposite of what the tutorial says it should do (ie, validating a non-valid name entry), even though I've followed the tutorial exactly.它似乎与教程所说的完全相反(即验证无效的名称条目),即使我完全按照教程进行了操作。 I've also searched the web and SO for more details on how assert_not works, but can't find any helpful details.我还搜索了网络和 SO 以获取有关assert_not如何工作的更多详细信息,但找不到任何有用的详细信息。 Here's the process I've went through.这是我经历的过程。

  1. Add a test that we know will fail:添加一个我们知道会失败的测试:

     require 'test_helper' class UserTest < ActiveSupport::TestCase def setup @user = User.new(name: "Example User", email: "user@example.com") end # resolves to true and passes test "should be valid" do assert @user.valid? end test "name should be present" do @user.name = " " assert_not @user.valid? end end

So far so good.到现在为止还挺好。 I understand this code perfectly well, and although the second test's wording is awkward, I interpret assert_not @user.valid?我完全理解这段代码,虽然第二个测试的措辞很尴尬,但我解释了assert_not @user.valid? to work like this: @user.valid?像这样工作: @user.valid? evaluates to true, since no validations have been set up, so the test thinks a name with all blank spaces is valid.评估为真,因为尚未设置验证,因此测试认为包含所有空格的名称是有效的。 This is preceded by an assert_not which converts a true value to false, and makes the test fail.这之前是一个assert_not ,它将真值转换为假值,并使测试失败。

  1. We add a validation test:我们添加一个验证测试:

     class User < ActiveRecord::Base validates :name, presence: true end

This sets a validation rule for the User model that ensures the :name object has content and is not nil, an empty string, or blank space.这为 User 模型设置了验证规则,以确保:name对象具有内容并且不是 nil、空字符串或空格。 Still good so far.到目前为止还是不错的。

  1. Here's where things get tricky.这就是事情变得棘手的地方。 At this point, the expression @user.valid?此时,表达式@user.valid? in our test should (and does) evaluate to false, since the validation rule won't allow a :name with only spaces in it.在我们的测试中应该(并且确实)评估为 false,因为验证规则不允许:name中只有空格。 I've added comments alongside this code to help my mind see what values are assigned and evaluated in this process:我在此代码旁边添加了注释,以帮助我了解在此过程中分配和评估的值:

     test "name should be present" do @user.name = " " # => name: " " email: "example@example.com" assert_not @user.valid? # => assert_not false => true end

@user.valid? evaluates to false, which makes the entire assert_not expression evaluate to true, and thus the test passes.计算结果为 false,这使得整个assert_not表达式的计算结果为 true,因此测试通过。 In pseudocode, this line could translate thusly: assert_not (is the user valid? no) ==> assert_not(false) ==> true .在伪代码中,这一行可以这样翻译: assert_not (is the user valid? no) ==> assert_not(false) ==> true Similarly, "We do not assert that the user is false", which evaluates to true.类似地,“我们不断言用户是假的”,其计算结果为真。

This is where my problem is: The test passes on an invalid value for :name , thus allowing a name consisting of blank spaces to be written to the database, when that's exactly the opposite of what we are trying to achieve, namely, preventing blank names from being written to db.这就是我的问题所在:测试传递了:name的无效值,从而允许将包含空格的名称写入数据库,这与我们试图实现的完全相反,即防止空白被写入数据库的名称。

  1. Conversely, I worked out this logic with a valid name:相反,我用一个有效的名称计算出这个逻辑:

     test "name should be present" do # => name: "Example User" email: "example@example.com" assert_not @user.valid? # assert_not true => false end

In this case, since @user.valid?在这种情况下,因为@user.valid? evaluates to true (since "Example User" is a valid name), assert_not @user.valid?评估为真(因为“示例用户”是有效名称), assert_not @user.valid? evaluates to false, the test fails, and our valid name does not get written to the database.评估为 false,测试失败,我们的有效名称不会写入数据库。 In pseudocode, this line could translate thusly: assert_not (is the user valid? yes) ==> assert_not(true) ==> false .在伪代码中,这一行可以这样翻译: assert_not (is the user valid? yes) ==> assert_not(true) ==> false Similarly, "We do not assert that the user is true", which evaluates to false.类似地,“我们不断言用户是真的”,其计算结果为假。 Because the test evaluates to false (even with a true/valid user name), this valid name is not written to the database.由于测试评估为假(即使用户名为真/有效),此有效名称不会写入数据库。

If someone could explain how this makes any sense, I'd greatly appreciate it, and detailed answers walking me through it would be even better.如果有人能解释这有什么意义,我将不胜感激,并且详细的答案会引导我完成它会更好。

The test passes on an invalid value for :name, thus allowing a name consisting of blank spaces to be written to the database...该测试传递了一个无效的 :name 值,从而允许将包含空格的名称写入数据库...

assert_not returns true (same as test passing) if the expression that follows, @user.valid? 如果后面的表达式@user.valid? assert_not返回真(与测试通过相同) @user.valid? , returns false. ,返回假。 In effect the test in section 3 says: We're not asserting that the user is valid.实际上,第 3 节中的测试说:我们没有断言用户是有效的。 Since that expectation/assertion is correct, it returns true and the test passes.由于该期望/断言是正确的,它返回 true 并且测试通过。 Nothing has been saved to the database.没有任何东西被保存到数据库中。

You can add a validation as you add a string " " consist two spaces您可以在添加字符串“”时添加验证,该字符串由两个空格组成

  class User < ActiveRecord::Base
   validates :name, presence: true, allow_blank: false
   validate :name_of_valid

   def name_of_valid
    self.errors.add :base, 'My string can not be empty' if self.name == "   " 
   end
end

and then进而

test "name should be present" do
    @user.name = "   "
    # => name: "   " email: "example@example.com"
    assert_not @user.valid? 
    # => assert_not true 
end

I had the same problem.我有同样的问题。 Only with presence: true the test fails and when I add allow_blank: false it passes.只有presence: true测试失败,当我添加allow_blank: false它通过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM