Skip to content

Let applications choose the model for an ambiguous table - #136

Merged
nertzy merged 1 commit into
masterfrom
choose-ambiguous-table-models
Oct 13, 2026
Merged

nertzy merged 1 commit into
masterfrom
choose-ambiguous-table-models

Conversation

@nertzy

@nertzy nertzy commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

Model-aware fixtures pick a model for each table from the loaded models and raise AmbiguousModelError when unrelated models share a table. Scripts, rake tasks, and one-off backfills often define a small row model for an existing table, so once an application eager-loads (typically in CI), the build stops and offers no way forward short of changing application code. Migration-local models are already ignored (#129), but this is the same pattern outside migrations.

This adds two settings:

  • model_classes maps table names to a model class or class name and is consulted before discovery. A mapped model must pass the same eligibility checks as a discovered one; otherwise the build raises ArgumentError naming the table and class.
  • prefer_conventional_models is off by default. When enabled and several unrelated models match a table, the one named table_name.classify is chosen if exactly one has that name; otherwise ambiguity still raises.

AmbiguousModelError now names both settings. The README documents them next to model discovery, and the changelog has an Added entry.

Tests cover a row model beside its application model with and without each setting, a mapping to a model for another table, a preference with no conventionally named candidate, and both settings applied through FixtureBuilder.configure.

Closes #135

Scripts, rake tasks, and one-off backfills often define their own model
for an existing table. Once the application eager-loads, that model ties
with the application model and the build raises AmbiguousModelError with
no way to proceed.

Add model_classes, which maps table names to models and is consulted
before discovery, and an opt-in prefer_conventional_models, which picks
the conventionally named model when exactly one ambiguous candidate has
that name. Ambiguity still raises by default, and the error names both
settings.
Copilot AI balanced review requested due to automatic review settings October 13, 2026 23:19
@nertzy
nertzy merged commit d1f18ae into master Oct 13, 2026
11 checks passed
@nertzy
nertzy deleted the choose-ambiguous-table-models branch October 13, 2026 23:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Missing mappings raise the wrong exception, STI mappings can omit rows, and validation occurs after destructive cleanup.

3 open findings
What changed in this PR

Adds configurable model selection for ambiguous fixture tables.

Changes:

  • Adds explicit model mappings and conventional-model preference.
  • Improves ambiguity guidance and documentation.
  • Adds resolver and integration tests.
File Description
lib/​fixture_builder/​model_resolver.rb Implements model-selection settings.
lib/​fixture_builder/​configuration.rb Exposes configuration options.
lib/​fixture_builder/​builder.rb Passes settings to the resolver.
lib/​fixture_builder/​ambiguous_model_error.rb Expands resolution guidance.
test/​model_resolver/​model_classes_test.rb Tests explicit mappings.
test/​model_resolver/​conventional_preference_test.rb Tests conventional preference.
test/​model_resolver/​ambiguous_model_error_test.rb Updates error assertions.
test/​support/​model_resolver_ambiguity_behavior.rb Updates shared ambiguity assertions.
README.md Documents both settings.
CHANGELOG.md Records the new functionality.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +131 to +134
resolver = ModelResolver.new(
connection_pool: ActiveRecord::Base.connection_pool,
model_classes: model_classes,
prefer_conventional_models: prefer_conventional_models
def mapped_model(table_name)
mapping = @model_classes.fetch(table_name)
model = mapping.is_a?(Module) ? mapping : mapping.to_s.constantize
return model if model < ActiveRecord::Base && eligible_model?(model, table_name)
Comment on lines +36 to +40
model = mapping.is_a?(Module) ? mapping : mapping.to_s.constantize
return model if model < ActiveRecord::Base && eligible_model?(model, table_name)

raise ArgumentError, "model_classes maps #{table_name} to #{model.name}, which is not an eligible model " \
"for that table: it must be concrete, named, use the table on the same connection, and have a primary key"
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.

Let applications choose the model for an ambiguous table

2 participants