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

Ruby on Rails嵌套表单创建实体的控制器测试问题

Rails嵌套表单创建实体的测试问题解决

问题场景

在Ruby on Rails项目中,Entity与UserEntityRole通过HMT(Has Many Through)关联,创建新实体时使用嵌套表单,控制器通过new和create分两步实现。但编写创建实体的测试代码时,因嵌套的user_entity_role参数错误导致测试失败——错误传入了id:0,让Rails误以为要更新已有记录,而实际上需要创建新的关联记录,且新实体的ID会由Rails自动关联到user_entity_role。

相关代码

模型代码

class Entity < ApplicationRecord
  has_many :invoices, dependent: :restrict_with_error
  has_many :user_entity_roles, dependent: :destroy
  accepts_nested_attributes_for :user_entity_roles
  has_many :users, through: :user_entity_roles, dependent: :restrict_with_error
  belongs_to :invoice_number_format
  has_many :debitors, dependent: :restrict_with_error
  validates_associated :user_entity_roles

  validates :company, presence: true
  validates :street, presence: true
  validates :house_number, presence: true
  validates :zip, presence: true
  validates :city, presence: true
end

class UserEntityRole < ApplicationRecord
  belongs_to :entity, touch: true
  belongs_to :user
  validates :entity_id, uniqueness: { scope: :user_id }
end

Entities控制器代码

def new
  @entity = Entity.new
  @entity.user_entity_roles.build
  @entity.user_entity_roles.first.user_id = Current.user.id
end

def create
  @entity = Entity.new(entity_params)
  if @entity.save
    redirect_to @entity
  else
    render :new, status: :unprocessable_entity
  end
end

控制器参数方法

def entity_params
  params.require(:entity).permit(
    :id, :company, :street, :house_number, :zip, :city, 
    :tax_number, :vat_id, :hrb, :managing_director, :iban, :bank, 
    :invoice_number_format_id,
    user_entity_roles_attributes: %i[id is_manager is_editor user_id]
  )
end

修正后的测试代码

问题出在测试参数中给user_entity_roles_attributes传入了id:0,创建新关联记录时不需要指定id,Rails会自动处理新记录的创建并关联到刚生成的Entity。同时可以增加对UserEntityRole计数的验证,让测试更完整:

test 'should create entity with valid params' do
  sign_in_as @user
  assert_difference -> { Entity.count }, 1 do
    assert_difference -> { UserEntityRole.count }, 1 do
      post entities_url, params: {
        entity: {
          company: 'MyString',
          street: 'MyString',
          house_number: 'MyString',
          zip: 'MyString',
          city: 'MyString',
          tax_number: 'MyString',
          vat_id: 'MyString',
          hrb: 'MyString',
          invoice_number_format_id: 2,
          user_entity_roles_attributes: {
            # 移除错误的id参数
            user_id: @user.id,
            is_manager: 1,
            is_editor: 1
          }
        }
      }
    end
  end
  # 验证关联记录的正确性
  entity = Entity.last
  assert_equal @user.id, entity.user_entity_roles.first.user_id
  assert entity.user_entity_roles.first.is_manager
  assert entity.user_entity_roles.first.is_editor
end

关键说明

  • 创建嵌套关联记录时,不要传入id参数,否则Rails会尝试更新对应ID的记录而非创建新记录。
  • 新创建的Entity的ID会由Rails自动赋值给user_entity_roles的entity_id,无需手动指定。
  • 增加对关联模型计数和属性的验证,能确保嵌套关联正确创建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:27:25