Probed at main a643ac7 (the runtime is unchanged at bc4acba), Linux x86-64, gcc 16.2.1 (Spinel 01d9d2f02).
Relation#ids answers the primary keys of a uuid-keyed model as Integers: the runtime reads #{@table}.id and calls .to_i on each value, and the sidecar seeds it Array[Integer]. So a uuid 44444444-4444-4444-8444-444444444441 comes back as 44444444, and a key starting with a letter as 0. The neighbours already carry string keys since #90 and #266: find casts through _cast_primary_key, the model's own finders take its key type, and pluck(:id) answers the stored value.
db/schema.rb:
ActiveRecord::Schema[8.1].define(version: 2026_01_01_000000) do
create_table "widgets", id: :uuid, force: :cascade do |t|
t.string "name"
t.boolean "active", default: true
end
end
app/controllers/widgets_controller.rb:
class WidgetsController < ApplicationController
def index
render plain: Widget.count.to_s
end
def exists
render plain: Widget.where(active: true).exists?(params[:id]).to_s
end
def ids
render plain: Widget.where(active: true).ids.join(",")
end
end
(config/routes.rb: root "widgets#index", get "widgets/:id/exists", to: "widgets#exists", get "widget_ids", to: "widgets#ids"; Widget < ApplicationRecord with no body.)
With one row, id = '44444444-4444-4444-8444-444444444441', after spin build:
| request |
Rails |
binary |
GET /widget_ids |
44444444-4444-4444-8444-444444444441 |
44444444 |
GET /widgets/44444444-4444-4444-8444-444444444441/exists |
true |
true |
GET /widgets/nope/exists |
false |
false |
The runtime, runtime/ruby/active_record/relation.rb:
# `ids` — primary keys, as integers.
def ids
prior = @select_sql
@select_sql = "#{@table}.id AS v"
rows = ActiveRecord.adapter.select_rows(to_sql)
@select_sql = prior
rows.map { |row| row["v"].to_i }
end
A model with self.primary_key = "identifier" would read the wrong column as well (I read that from the code rather than ran it).
A possible shape: select @model.primary_key and map each value through @model._cast_primary_key (as find does), with the ids seed widened for string-keyed apps the way widen_key_contract widens id. I have not tried that against the integer-keyed corpus, where the narrower Array[Integer] may matter to the typing, so I'm leaving the approach to you.
Found while compiling a Rails API app with --target spinel.
Probed at main a643ac7 (the runtime is unchanged at bc4acba), Linux x86-64, gcc 16.2.1 (Spinel 01d9d2f02).
Relation#idsanswers the primary keys of a uuid-keyed model as Integers: the runtime reads#{@table}.idand calls.to_ion each value, and the sidecar seeds itArray[Integer]. So a uuid44444444-4444-4444-8444-444444444441comes back as44444444, and a key starting with a letter as0. The neighbours already carry string keys since #90 and #266:findcasts through_cast_primary_key, the model's own finders take its key type, andpluck(:id)answers the stored value.db/schema.rb:app/controllers/widgets_controller.rb:(
config/routes.rb:root "widgets#index",get "widgets/:id/exists", to: "widgets#exists",get "widget_ids", to: "widgets#ids";Widget < ApplicationRecordwith no body.)With one row,
id = '44444444-4444-4444-8444-444444444441', afterspin build:GET /widget_ids44444444-4444-4444-8444-44444444444144444444GET /widgets/44444444-4444-4444-8444-444444444441/existstruetrueGET /widgets/nope/existsfalsefalseThe runtime,
runtime/ruby/active_record/relation.rb:A model with
self.primary_key = "identifier"would read the wrong column as well (I read that from the code rather than ran it).A possible shape: select
@model.primary_keyand map each value through@model._cast_primary_key(asfinddoes), with theidsseed widened for string-keyed apps the waywiden_key_contractwidensid. I have not tried that against the integer-keyed corpus, where the narrowerArray[Integer]may matter to the typing, so I'm leaving the approach to you.Found while compiling a Rails API app with
--target spinel.