Skip to content

ActiveRecordRelations cannot generate an RBI for an Active Record model with a composite primary key #2723

Description

@jgrau

Problem

ActiveRecordRelations cannot generate an RBI for an Active Record model with a composite primary key. When generating ids, it passes
constant.primary_key—an Array—to ActiveRecordColumnTypeHelper#type_for, whose argument is typed as String.

Reproduced with Tapioca 0.19.2 and Rails 8. The same call is present in v0.20.0 and current main, though I have only run this reproduction against
0.19.2.

Minimal reproduction

With tapioca 0.19.2, Active Record 8, and the PostgreSQL adapter available, run bundle exec ruby repro.rb:

require "active_record"
require "active_record/connection_adapters/postgresql/oid/uuid"
require "tapioca/internal"
require "tapioca/dsl/compilers/active_record_relations"

class CompositeRecord < ActiveRecord::Base
  self.primary_key = %w[listing_id checkin_on checkout_on]

  def self.table_exists? = true

  def self.columns_hash
    %w[listing_id checkin_on checkout_on].to_h do |name|
      [name, Struct.new(:null).new(false)]
    end
  end

  def self.attribute_types
    {
      "listing_id" => ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Uuid.new,
      "checkin_on" => ActiveRecord::Type::Date.new,
      "checkout_on" => ActiveRecord::Type::Date.new,
    }
  end
end

compiler = Tapioca::Dsl::Compilers::ActiveRecordRelations
pipeline = Tapioca::Dsl::Pipeline.new(
  requested_constants: [CompositeRecord],
  requested_compilers: [compiler],
)
root = RBI::Tree.new
compiler.new(pipeline, root, CompositeRecord).decorate

The metadata is supplied in memory to keep the reproduction database-free; it exercises the actual compiler.

Actual result

  TypeError: Parameter 'attribute_name': Expected type ::String,
  got type Array with value ["listing_id", "checkin_on", "checkout_on"]
  Caller: .../active_record_relations.rb:801
  Definition: .../active_record_column_type_helper.rb:60

Expected result

Generation succeeds, with ids returning typed tuples for these columns—for example, T::Array[[::String, ::Date, ::Date]].

ActiveRecordColumnTypeHelper#type_for("id") already delegates to its composite-aware id_type method. Could the Relations compiler use that path for ids,
while preserving scalar/nonstandard primary-key behavior?

Related earlier work: #1966 addresses composite find overloads; #2007 addresses composite column types.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions