From 1835e95c287be0c2b7a5889bc05614ce2c88dd35 Mon Sep 17 00:00:00 2001 From: Jonas Grau <108088+jgrau@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:47:54 +0200 Subject: [PATCH] Fix relation ids for composite primary keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the column helper’s composite-aware id path so RBI generation accepts an array primary key and returns typed tuples. Cover composite and nonstandard scalar keys in the Relations compiler specs. Pax-Session: interactive:terminal/01a0e468-c6cd-7049-8a4c-01fc37048a82 Pax-Origin: interactive:terminal Co-authored-by: Pax <262454628+hey-pax@users.noreply.github.com> --- .../dsl/compilers/active_record_relations.rb | 3 +- .../compilers/active_record_relations_spec.rb | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/tapioca/dsl/compilers/active_record_relations.rb b/lib/tapioca/dsl/compilers/active_record_relations.rb index 1dea3adb7..ccdec2524 100644 --- a/lib/tapioca/dsl/compilers/active_record_relations.rb +++ b/lib/tapioca/dsl/compilers/active_record_relations.rb @@ -794,8 +794,7 @@ def create_common_methods constant, column_type_option: Tapioca::Dsl::Helpers::ActiveRecordColumnTypeHelper::ColumnTypeOption::Persisted, ) - primary_key = constant.primary_key - getter_type, _setter_type = column_type_helper.type_for(primary_key) + getter_type, _setter_type = column_type_helper.type_for("id") type = getter_type create_common_method("ids", return_type: "T::Array[#{type}]") else diff --git a/spec/tapioca/dsl/compilers/active_record_relations_spec.rb b/spec/tapioca/dsl/compilers/active_record_relations_spec.rb index e7a0f3dbc..af3ff4e1f 100644 --- a/spec/tapioca/dsl/compilers/active_record_relations_spec.rb +++ b/spec/tapioca/dsl/compilers/active_record_relations_spec.rb @@ -778,6 +778,54 @@ def not(opts, *rest); end assert_equal(expected, rbi_for(:Post)) end + it "generates typed ids for a nonstandard scalar primary key" do + add_ruby_file("schema.rb", <<~RUBY) + ActiveRecord::Migration.suppress_messages do + ActiveRecord::Schema.define do + create_table :posts, id: :string, primary_key: :code + end + end + RUBY + + add_ruby_file("post.rb", <<~RUBY) + class Post < ActiveRecord::Base + end + RUBY + + expected = indented(<<~RBI, 4) + sig { returns(T::Array[::String]) } + def ids; end + RBI + + assert_includes(rbi_for(:Post), expected) + end + + it "generates typed ids for composite primary keys" do + add_ruby_file("schema.rb", <<~RUBY) + ActiveRecord::Migration.suppress_messages do + ActiveRecord::Schema.define do + create_table :posts, primary_key: [:listing_id, :checkin_on, :checkout_on] do |t| + t.string :listing_id, null: false + t.date :checkin_on, null: false + t.date :checkout_on, null: false + end + end + end + RUBY + + add_ruby_file("post.rb", <<~RUBY) + class Post < ActiveRecord::Base + end + RUBY + + expected = indented(<<~RBI, 4) + sig { returns(T::Array[[::String, ::Date, ::Date]]) } + def ids; end + RBI + + assert_includes(rbi_for(:Post), expected) + end + it "generates handles composite primary keys" do add_ruby_file("post.rb", <<~RUBY) class Post < ActiveRecord::Base