factory_bot icon indicating copy to clipboard operation
factory_bot copied to clipboard

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

Open StefSchenkelaars opened this issue 3 years ago • 1 comments

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
#!/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 <filename>`

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

StefSchenkelaars avatar Jun 03 '21 06:06 StefSchenkelaars

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.

aledustet avatar Jul 30 '21 16:07 aledustet

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

tatethurston avatar Oct 24 '23 17:10 tatethurston