Skip to content

Identify a uuid primary key by its Active Record type - #1838

Open
IslamElsayed wants to merge 2 commits into
thoughtbot:mainfrom
IslamElsayed:uuid-primary-key-by-type
Open

IslamElsayed wants to merge 2 commits into
thoughtbot:mainfrom
IslamElsayed:uuid-primary-key-by-type

Conversation

@IslamElsayed

Copy link
Copy Markdown

Fixes #1618.

build_stubbed picks the id from an integer sequence unless the primary key is a uuid, and it decided that by comparing the column's sql_type to "uuid":

column.respond_to?(:sql_type) && column.sql_type == "uuid"

That is PostgreSQL's name for the type. SQL Server calls the same thing uniqueidentifier, so the check failed, next_id fell through to @@next_id += 1, and assigning an Integer to a uuid attribute left id nil — the symptom in the issue.

The adapters disagree on the name but agree on the Active Record type. From the SQL Server adapter's own source:

# lib/active_record/connection_adapters/sqlserver/type/uuid.rb
class Uuid < String
  def type
    :uuid
  end

  def sqlserver_type
    "uniqueidentifier"
  end
end

# sqlserver_adapter.rb
m.register_type "uniqueidentifier", SQLServer::Type::Uuid.new

So this asks the column for type first and keeps the sql_type comparison as a fallback for anything that reports the name without mapping the type.

Testing

Three examples in spec/factory_bot/strategy/stub_spec.rb, driven by a column double so they need no SQL Server:

  • type :uuid / sql_type "uniqueidentifier" → uuid id (the reported case)
  • sql_type "uuid" with no type → uuid id (the existing PostgreSQL path)
  • type :integer → still an Integer id

I checked they are not vacuous by breaking the fix both ways: reverting to the sql_type-only check fails the first, and dropping the sql_type branch fails the second. The existing spec/acceptance/stub_spec.rb uuid examples still pass unchanged.

Full suite: 777 examples, 0 failures. standardrb clean on both files. Run under Ruby 3.3.5 rather than the 4.0.1 in .tool-versions, since the gemspec allows >= 3.0.0.

I do not have SQL Server to hand, so the adapter behaviour above is read from its source rather than executed — correct me if uniqueidentifier reaches column_for_attribute differently in practice.

Disclosure: I use AI assistance when working on patches, and I check and test everything before submitting.

build_stubbed assigns an id from an integer sequence unless the primary
key is a uuid, which it decided by comparing the column's sql_type to
"uuid". That is PostgreSQL's name for it. SQL Server calls the same thing
"uniqueidentifier", so the check failed there, the id came from the
integer sequence, and assigning an Integer to a uuid attribute left it
nil -- the symptom reported in thoughtbot#1618.

Adapters disagree on the name but agree on the type: the SQL Server
adapter registers "uniqueidentifier" as SQLServer::Type::Uuid, whose
#type is :uuid. Ask the column for its Active Record type first and keep
the sql_type comparison for anything that reports the name without
mapping the type.

Closes thoughtbot#1618
@IslamElsayed

Copy link
Copy Markdown
Author

Friendly ping on this one. CI hasn't run yet because it's waiting for first-time contributor approval. Could a maintainer approve the workflows when there's a moment? Happy to make any changes. (I used an AI assistant while preparing this PR, and I reviewed and tested the change myself.)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build_stubbed does not fill id for uuid column type with SQLServer

1 participant