thoughtbot / factory_bot

A library for setting up Ruby objects as test data.
https://thoughtbot.com
MIT License
7.9k stars 2.6k forks source link

`build_stubbed` does not fill `id` for `uuid` column type #1498

Closed StefSchenkelaars closed 11 months ago

StefSchenkelaars commented 3 years ago

Description

When using uuid as the primary key type, they build_stubbed method does not automatically fill the id column. I would assume that this is filled independent of the column type.

Reproduction Steps

Reproduction script ```ruby #!/usr/bin/env ruby 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 "pg" end require "active_record" require "factory_bot" require "minitest/autorun" require "logger" ActiveRecord::Base.establish_connection(adapter: "postgresql", database: "factory_bot_test") ActiveRecord::Base.logger = Logger.new(STDOUT) ActiveRecord::Schema.define do enable_extension 'pgcrypto' create_table :int_posts, force: true do |t| t.string :body end create_table :uuid_posts, id: :uuid, force: true do |t| t.string :body end end class IntPost < ActiveRecord::Base end class UuidPost < ActiveRecord::Base end FactoryBot.define do factory :int_post do body { "Post body" } end factory :uuid_post do body { "Post body" } end end class FactoryBotTest < Minitest::Test def test_working_with_int post = FactoryBot.build_stubbed(:int_post) refute_nil post.id end def test_failing_with_uuid post = FactoryBot.build_stubbed(:uuid_post) refute_nil post.id end end # Run the tests with `ruby ` ```

Expected behavior

When you use build_stubbed, the primary key is always set. Also if you use the uuid type.

Actual behavior

The id of the generated instance is nil.

System configuration

factory_bot version: 6.2.0 rails version: 6.1.3.2 ruby version: 3.0.1

aledustet commented 3 years ago

Thanks for opening an issue @StefSchenkelaars . We did some exploration and it seems like an issue with the type of the column. This could be something we support, but the assumption made to auto-generate the primary_key value is a self incrementing number, the class variable @@next_id on the stub strategy. This is a good place to start if you're interested in exploring a bit more!

As a workaround, you could specify the id when the value is built, or you can try adding it on your factory definition.

post = FactoryBot.build_stubbed(:uuid_post, id: SecureRandom.uuid)

# Or on the definition

factory :uuid_post do
  id { SecureRandom.uuid }
  body { "Post body" }
end

I think a first action we could take is to add a note on the GETTING_STARTED.md doc, mentioning that the primary key stub only works for numeric primary keys.

tatethurston commented 10 months ago

A third workaround if you have a number of models with uuids, create a global trait with_id, for easy removal once support lands:

# frozen_string_literal: true

# Temporary workaround for https://github.com/thoughtbot/factory_bot/issues/1498 until https://github.com/thoughtbot/factory_bot/pull/1583 is released.
# Once #1583 is released, remove this trait and use build_stubbed directly.
FactoryBot.define do
  trait :with_id do
    id { SecureRandom.uuid }
  end
end