You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails测试问题:如何传递含外键的参数通过创建动作校验

Rails ContactsController create动作测试422错误排查与解决

测试ContactsController的create动作时出现以下失败:

Failure:
ContactsControllerTest#test_should_post_create [test/controllers/contacts_controller_test.rb:36]:
Expected response to be a <3XX: redirect>, but was a <422: Unprocessable Entity>

已确认授权逻辑正常,其他测试无问题,怀疑是外键参数传递错误,尝试过用@salutation.id和@debitor.id但未解决,以下是相关代码:

模型代码(Contact)

class Contact < ApplicationRecord
    validates :last_name, presence: true
    validates :email, format: {
        with: URI::MailTo::EMAIL_REGEXP
    }
    belongs_to :salutation
    belongs_to :debitor
end

控制器代码(ContactsController)

class ContactsController < ApplicationController
  def create
      @contact = Contact.new(contact_params)
      @debitors = Debitor.all
      @salutations = Salutation.all
    
      if @contact.save 
        redirect_to contacts_path
      else
        render :new, status: :unprocessable_entity
      end
  end

  private
  def contact_params
    params.require(:contact).permit(:last_name, :first_name, :email, :salutation_id, :debitor_id)
  end
end

测试代码(ContactsControllerTest)

require "test_helper"

class ContactsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @user = users(:lazaro_nixon)
    @contact = contacts(:one)
    @salutation = salutations(:one)
    @debitor = debitors(:one)
  end

  test "should post create" do
    sign_in_as @user

    post contacts_url, :params => { :contact => { last_name: "Lastname", first_name: "Firstname", email: "test@test.com", salutation: @salutation, debitor: @debitor }}
    assert_response :redirect
    follow_redirect!
    assert_response :success
  end
end

Fixtures数据

contacts.yml

one:
  last_name: MyString
  first_name: MyString
  email: MyString
  salutation: one
  debitor: one

salutations.yml

one:
  salutation: MyString

debitors.yml

one:
  company: MyString
  street: MyString
  house_number: MyString
  zip: 1
  city: MyString
  payment_terms: one

问题原因与解决方法

核心问题是测试中传递的参数键名错误:控制器的contact_params只允许接收salutation_id和debitor_id,但测试代码里传的是salutation和debitor对象,这会导致参数无法被正确强转,进而触发模型的belongs_to关联验证失败(因为外键字段为空)。

修改测试中的参数部分,将对象替换为对应的ID:

post contacts_url, params: { 
  contact: { 
    last_name: "Lastname", 
    first_name: "Firstname", 
    email: "test@test.com", 
    salutation_id: @salutation.id, 
    debitor_id: @debitor.id 
  }
}

另外需要确认:

  1. Fixtures中的salutations(:one)和debitors(:one)已经被正确加载(测试的setup方法已经实例化这两个对象,正常情况下没问题);
  2. 测试中的email格式符合验证规则(test@test.com是合法格式,满足URI::MailTo::EMAIL_REGEXP);
  3. last_name字段已提供有效值(测试中传了"Lastname",满足存在性验证)。

修改后重新运行测试,应该能正常通过,返回预期的重定向响应。

内容的提问来源于stack exchange,提问作者Ricky883249

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:38:11