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 } }
另外需要确认:
- Fixtures中的
salutations(:one)和debitors(:one)已经被正确加载(测试的setup方法已经实例化这两个对象,正常情况下没问题); - 测试中的
email格式符合验证规则(test@test.com是合法格式,满足URI::MailTo::EMAIL_REGEXP); last_name字段已提供有效值(测试中传了"Lastname",满足存在性验证)。
修改后重新运行测试,应该能正常通过,返回预期的重定向响应。
内容的提问来源于stack exchange,提问作者Ricky883249
相关产品推荐
相关产品推荐

