【问题标题】:Can't test controller render due to ActiveRecord::StatementInvalid:error由于 ActiveRecord::StatementInvalid:error 无法测试控制器渲染
【发布时间】:2016-12-22 12:19:50
【问题描述】:

好的,我有这个控制器代码:

def create
    @foo = Foo.new(user: User.new(user_params))
    if @foo.save
      redirect_to foos_path
    else
      render :new
    end
end

并且我想测试当用户电子邮件无效时它是否重新呈现新页面。为此,我创建了这个测试:

it "should re-render the new template" do
    post :create, params: { user: attributes_for(:user, email: "abc.com") } }
    expect(response).to render_template(:new)
end

但是,由于此错误,测试失败:

 Failure/Error: if @foo.save

 ActiveRecord::StatementInvalid:
   PG::NotNullViolation: ERROR:  null value in column "user_id" violates not-null constraint
   DETAIL:  Failing row contains (260, null).
   : INSERT INTO "foos" DEFAULT VALUES RETURNING "id"

Foo 表有一个

t.belongs_to :user, null: false, index: true

这样它就不会在没有用户的情况下添加 foo。

我认为这个错误实际上是一种期望的行为,因为它会阻止 foo 在没有用户的情况下保存,并且用户不能使用无效的电子邮件保存。但是我仍然需要测试它,所以我测试它错误吗?我怎样才能做到这一点?有什么遗漏吗?

提前致谢!

【问题讨论】:

    标签: ruby-on-rails activerecord rspec


    【解决方案1】:

    你的问题不是很清楚,但我猜这里是错误:

    @foo = Foo.new(user: User.new(user_params))
    

    User.new 不会将用户保存到数据库,因此您将没有 ID,并且您的 user_id 非空约束将失败。

    用途:

    user = User.create(user_params)
    @foo = Foo.new(user: user)
    

    改为

    【讨论】:

    • 这正是问题所在。但无论如何它应该保存它..我尝试了你建议的方式,假设问题可能是它会尝试同时保存两者,但它仍然没有工作。
    • 我猜你的用户由于验证失败而没有被保存
    • 好吧,我改变了我的控制器来做到这一点:if @foo.user.save && @foo.save 而不是只是 if @foo.save 并且它有效,但它们不应该完全相同吗?
    • @RafaelCosta,如果@foo.save返回false,用户仍然会被创建。
    【解决方案2】:

    你可以试试:

    @foo = Foo.new
    @foo.build_user(user_params)
    @foo.save
    

    它应该同时保存用户和 foo。

    这将创建一个事务,以便在验证 foo 和用户之前不会将任何记录保存到数据库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多