【问题标题】:This should not be nil这不应该是零
【发布时间】:2014-04-26 23:42:54
【问题描述】:

我有一个简单的测试:

it "should create a post through a user for a blog." do
  @user.blogs.create(title: @blog.title)
  @user.blogs.find_by_title(@blog.title).posts.create(title: 'some title')
  post = Post.find_by_title('some title')
  post.title.should == 'some title'
end

这失败了。为什么?因为我们没有任何用户博客。好的,让我们在他们的:

it "should create a post through a user for a blog." do
  @user.blogs.create(title: @blog.title)
  binding.pry
  @user.blogs.find_by_title(@blog.title).posts.create(title: 'some title')
  post = Post.find_by_title('some title')
  post.title.should == 'some title'
end

现在在控制台中,让我们看看@user.blogs 是否给了我们任何东西。

@user.blogs
=> [#<Blog id: nil, title: "user_blog_26">]

好的....但这不是整个命令。让我们看看@blogs 有没有什么。

@blog
=> #<Blog id: 26, title: "user_blog_26">

好的,我们得到了一些结果,我们看到@user 与他们关联了相同的博客。 (虽然@user.blogs中缺少id……(注意:用户与博客的关系为:User has_and_belongs_to_many :blogs, join_table: 'blogs_users'

那么让我们做吧:

@user.blogs.find_by(title: @blog.title)
=> nil

嗯.....

怎么了?

  • 一个:我的用户博客关联没有 id。
  • :@user.blogs,返回该用户的所有博客,但@user.blogs.find_by(title: @blog.title) 返回nil?哦哦

怎么了?

额外的信息,以获得乐趣

模型

class User < ActiveRecord::Base
  include Promiscuous::Subscriber
  subscribe :first_name, :email, :user_name, :last_name

  has_and_belongs_to_many :blogs, join_table: 'blogs_users'
  has_many :posts, through: :blogs

  validates :first_name, presence: true
  validates :email, presence: true, uniqueness: true
  validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i

end


class Blog < ActiveRecord::Base
  has_many :posts

  validates :title, presence: true, uniqueness: true
end

【问题讨论】:

  • 尝试使用.build而不是.create

标签: ruby-on-rails rspec entity-relationship relationship models


【解决方案1】:
@blog
=> #<Blog id: 26, title: "user_blog_26">

@blog 分配了一个id。所以,这意味着它在blogs 表中的现有记录与id = 26

@user.blogs.create(title: @blog.title)

此行表示在 blogs 表中新建一条标题与@blog.title 相同的记录(即user_blog_26

现在,在 Blog 模型中,您拥有

validates :title, presence: true, uniqueness: true ## title must be unique

title 字段的唯一性检查。因此,显然@user.blogs.create(title: @blog.title) 失败,因为标题为user_blog_26 的记录已经存在于blogs 表中(在此处回忆@blog)。这就是为什么@user.blogs 将带有id = nil 的博客显示为associated blog 创建失败的原因。

@user.blogs.find_by(title: @blog.title)
=> nil

因为标题为user_blog_26associated blog 不是为@user 创建的。此查询返回nil

可能的解决方案

@blog 引用的数据库中已经有一条blog 记录。要将该博客分配给您的 @user,只需更新以下示例:

it "should create a post through a user for a blog." do
  @user.blogs << @blog ## This will set @blog.user_id = @user.id
  @user.blogs.find_by_title(@blog.title).posts.create(title: 'some title')
  post = Post.find_by_title('some title')
  post.title.should == 'some title'
end

【讨论】:

    【解决方案2】:

    在测试您的代码时,您应该让测试与外界隔离 - 它们不应通过或失败,因为您的真实数据库缺少行或存在意外行。

    因此,您应该使用某种方法,在每次测试开始时设置数据库以包含测试所需的内容,并且在测试结束时,您应该拆除数据库,为下一次测试做好准备。

    有一些宝石可以帮助您执行此策略,例如database cleaner。使用其中之一,您的测试将以更可预测的方式运行。

    【讨论】:

    • 我的测试很完美。他们是最棒的。不要评论。
    猜你喜欢
    • 2020-11-30
    • 2014-05-07
    • 2016-12-30
    • 2013-04-13
    • 1970-01-01
    • 2014-11-06
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多