Skip to content

Associations cannot override trait-defined ID attributes since v6.5.5 #1767

@oehlschl

Description

@oehlschl

Description

#1709 introduces surprising behavior, particularly for Rails apps, where associations can no longer override traits that set those associations by ID. This is is particularly surprising in the Rails case, where developers can generally expect setting association IDs and associations themselves to behave similarly.

There may be a best-practices argument for encouraging developers to not set both the ID and association attributes, but without a way of enforcing that, it's not a particularly scalable solution, and unfortunately the failure mode for this new behavior isn't terribly obvious.

Reproduction Steps

Here's the modified reproduction script. This test passes in 6.5.4 but fails in 6.5.5.

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"
  git_source(:github) { |repo| "https://github.com/#{repo}.git" }
  gem "factory_bot", "~> 6.0"
  gem "activerecord"
  gem "sqlite3"
end

require "active_record"
require "factory_bot"
require "minitest/autorun"
require "logger"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.string :name
  end
  
  create_table :posts, force: true do |t|
    t.string :body
    t.integer :user_id
  end
end

class User < ActiveRecord::Base
end

class Post < ActiveRecord::Base
  belongs_to :user
end

FactoryBot.define do
  factory :user do
    name { "Test User" }
  end
  
  factory :post do
    body { "Post body" }
    association :user
    
    trait :with_system_user_id do
      user_id { 999 }
    end
  end
end

class FactoryBotTest < Minitest::Test
  def test_association_overrides_trait_user_id
    # This test passes in 6.5.4 but fails in 6.5.5
    user = FactoryBot.create(:user)
    post = FactoryBot.build(:post, :with_system_user_id, user: user)
    
    assert_equal user.id, post.user_id, 
      "Association should override trait's user_id. Got #{post.user_id} instead of #{user.id}"
  end
end

Expected behavior

We expect post.user_id to be user.id and not 999

Actual behavior

post.user_id is still the ID set in the trait (999)

System configuration

factory_bot version: 6.5.5
rails version: 7.1
ruby version: 3.4.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions