1

我正在关注 Michael Hartl 的 RoR 教程,但在测试我的代码时出现以下错误。我似乎无法弄清楚为什么我的对象没有通过有效。

我的 user.rb 文件:

class User < ActiveRecord::Base

  before_save { |user| user.email = user.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, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
end

这是我的 user_rspec.rb:

    require 'spec_helper'

describe User do

  before { @user = User.new(name: "bobo", email: "user@example.com")  }

  subject { @user }

  it { should respond_to(:name) }
  it { should respond_to(:email) }

  it { should be_valid }

  describe "when name is not present" do
    before { @user.name = " "}

    it { should_not be_valid}
  end

  describe "when email is not present" do
    before { @user.email = " "}

    it { should_not be_valid}
  end

  describe "when name is too long" do
    before { @user.name = "a" * 51}

    it { should_not be_valid}
  end

  describe "when email format is invalid" do
    it "should be invalid" do
      addresses = %w[user@foo,com user_at_foo.org example-user@foo.]
      addresses.each do |invalid_address|
        @user.email = invalid_address
        @user.should_not be_valid
      end
    end
  end

  describe "when email format is valid" do
    it "should be valid" do 
      addresses = %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn]
      addresses.each do |valid_address|
        @user.email = valid_address
        @user.should be_valid
      end
    end
  end

  describe "when email address is already taken" do

    before do
      user_with_same_email =  @user.dup
      user_with_same_email.email = @user.email.upcase
      user_with_same_email.save
    end

    it {should_not be_valid}

  end

end

当我运行我的测试时,我收到以下错误:失败:

  1) User 
     Failure/Error: it { should be_valid }
       expected valid? to return true, got false
     # ./spec/models/user_spec.rb:12:in `block (2 levels) in <top (required)>'

Finished in 0.21355 seconds
9 examples, 1 failure

Failed examples:

rspec ./spec/models/user_spec.rb:12 # User `

当我在 Rails 控制台中运行 user_with_same_email.errors 时,我得到以下答案:

ruby-2.0.0-p247 :001 > user = User.new(name: "bobo", email: "user@example.com")
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at:     nil> 
ruby-2.0.0-p247 :002 > user_with_same_email =  user.dup
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at: nil> 
ruby-2.0.0-p247 :003 > user_with_same_email.valid?
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") =     LOWER('user@example.com') LIMIT 1
 => true 
ruby-2.0.0-p247 :004 > user_with_same_email.errors
 => #<ActiveModel::Errors:0x007fad6491f780 @base=#<User id: nil, name: "bobo", email:    "user@example.com", created_at: nil, updated_at: nil>, @messages={}> 
ruby-2.0.0-p247 :005 >

如您所见,该错误未传递任何消息。

有人知道我该如何解决这个错误吗?

谢谢!

添加:

当我尝试使用已保存的电子邮件保存用户时,似乎出现了错误。

$ rails console --sandbox
Loading development environment in sandbox (Rails 4.0.0)
Any modifications you make will be rolled back on exit
ruby-2.0.0-p247 :001 > user = User.new(name: "bobo", email: "user@example.com")
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at:         nil> 
ruby-2.0.0-p247 :002 > user.save
   (0.1ms)  SAVEPOINT active_record_1
  User Exists (0.2ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") =     LOWER('user@example.com') LIMIT 1
  SQL (3.3ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES       (?, ?, ?, ?)  [["created_at", Wed, 16 Oct 2013 10:15:19 UTC +00:00], ["email",     "user@example.com"], ["name", "bobo"], ["updated_at", Wed, 16 Oct 2013 10:15:19 UTC +00:00]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
 => true 
    ruby-2.0.0-p247 :003 > user_with_same_email =  user.dup
 => #<User id: nil, name: "bobo", email: "user@example.com", created_at: nil, updated_at: nil> 
ruby-2.0.0-p247 :004 > user_with_same_email.save
   (0.1ms)  SAVEPOINT active_record_1
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user@example.com') LIMIT 1
   (0.1ms)  ROLLBACK TO SAVEPOINT active_record_1
 => false 
ruby-2.0.0-p247 :005 > 

我不确定为什么会发生这种情况。我的验证不应该解决这个问题吗?

谢谢!

4

3 回答 3

0

如前所述,错误消息来自@user.errors.messagescontains {:email=>["has already been taken"]}

您可以通过添加到您的spec_helper.rb(在RSpec.configure do |config|块中)来初步解决此问题:

# clears user table
config.before(:suite) do
  User.destroy_all
end

但我不相信这个解决方案。看来,用户不会在测试用例之后破坏自己。

于 2014-04-15T20:54:04.667 回答
0

我的测试也失败了

  it { should be_Valid }

我的 Rails 控制台会话(上图) user.valid 为真

下面的更正测试

it { should be_valid }

大写的“be_Valid”是问题

于 2014-08-15T18:06:28.523 回答
0

您传递的名称少于 50 个字符,并且您的电子邮件与您制作的正则表达式匹配。唯一剩下的就是电子邮件的唯一性。我敢打赌,您没有在规格之间正确清理数据库。您可以通过将您的should be_valid规格扩展到此来确认吗?

it "is valid" do
  subject.valid?
  subject.errors.full_messages.should eq []
end

调用valid?将填充错误数组,然后规范将失败并显示错误消息。

如果电子邮件已被占用,请尝试使用database_cleaner https://github.com/bmabey/database_cleaner#rspec-example(您必须先将其添加到您的电子邮件中,然后Gemfile才能使用它。

于 2013-10-23T13:16:13.590 回答