Skip to content

docs+model: guides and CLAUDE.md use non-existent tableName("x") setter — silent no-op, models fall back to the convention table (real setter is table()) #3079

Closed

Description

@bpamiri

Summary

tableName() on models is a zero-argument getter (vendor/wheels/model/miscellaneous.cfc:177); the setter is table(name) (miscellaneous.cfc:35). CFML silently accepts the extra positional argument, so tableName("vw_legacy_users") in config() does nothing — the model keeps its convention table and the first finder throws Wheels.TableNotFound (or silently hits the wrong table if a convention-named one exists). Six docs locations teach the broken form; two independent batch-2 verifiers hit it live.

Repro (origin/develop 840274b, Lucee 7 + Adobe 2023)

Model copied verbatim from basics/database-and-multiple-datasources.mdx:53-60 (dataSource(...); tableName(...); setPrimaryKey(...)): first finder → Wheels.TableNotFound ... pattern [tenantwidgets] — the override silently never applied. Replacing with table(...) made every probe pass on both engines (per-model datasource routing, finders, query builder, transactions). Framework tests use the correct form (vendor/wheels/tests/specs/model/crudSpec.cfc:1211 .table("tbl_authors")); table() has been the setter since the cfm→cfc conversion — code is intentional, docs are wrong.

Affected docs

  • web/sites/guides/src/content/docs/v4-0-0/basics/database-and-multiple-datasources.mdx:57,91
  • web/sites/guides/src/content/docs/v4-0-0/basics/models-and-the-orm.mdx:51,59
  • web/sites/guides/src/content/docs/v4-0-0/testing/fixtures-and-test-data.mdx:140 (independently confirmed live by the testing-guides verifier — the TestPost example silently resolves the conventional table)
  • web/sites/guides/src/content/docs/v4-0-0/core-concepts/conventions-over-configuration.mdx:38
  • web/sites/guides/src/content/docs/v4-0-0/core-concepts/mvc-in-wheels.mdx:57
  • repo CLAUDE.md:261 (Model Quick Reference — likely the contamination source; AI agents keep regenerating the broken form)

Proposed direction

  1. Docs: replace every tableName("X") with table("X") at the sites above (CLAUDE.md included, so generated code stops propagating it).
  2. Ergonomics (recommended in addition): add a setter overload — tableName(string name) delegating to table() when an argument is passed, returning the current name otherwise — matching the Migrator: t.references() API quirks — 'referenceNames' (not 'columnNames'), and produces '<x>id' without underscore #2781/Migrator: primaryKey(name=...) is an argument-naming outlier #2803 alias precedent. If rejected, at least throw in development when tableName() receives an argument so the mistake fails loudly.

Acceptance

  • Zero tableName(" setter-style call sites remain under web/sites/guides/ or in CLAUDE.md.
  • Either the overload exists with a spec, or a dev-mode throw exists with a spec.

Reported by the guide-behavioral-audit P1 batch 2 (work items p1-13-datasources claim ds-07, p1-15-testing claim FIX-03-adjacent fixtures finding; live on Lucee 7 + Adobe 2023).

Activity

  1. wheels-bot commented on Jun 12, 2026

    @wheels-bot
    Contributor

    Wheels Bot — Triage

    Classified as bug.

    Following documented usage produces observable wrong behavior: tableName("vw_legacy_users") in config() is a silent no-op, so the model keeps its convention table and the first finder throws Wheels.TableNotFound. Verified against source — table(required any name) is the setter (vendor/wheels/model/miscellaneous.cfc:35) and tableName() is the zero-arg getter (vendor/wheels/model/miscellaneous.cfc:177), exactly as reported. The framework code is intentional; the defect is in the docs/CLAUDE.md that teach the non-existent setter, plus the requested ergonomics gap.

    Suspected layer

    model — see vendor/wheels/model/CLAUDE.md and the Model Quick Reference in repo CLAUDE.md for canonical patterns.

    Fix sketch

    Two-part change. (1) Docs: replace every setter-style tableName("X") with table("X") at the six named sites under web/sites/guides/.../v4-0-0/ and at repo CLAUDE.md:261 (the likely contamination source for regenerated code). (2) Model: add a tableName(string name) setter overload in vendor/wheels/model/miscellaneous.cfc that delegates to table() when an argument is passed and returns the current name otherwise — matching the #2781/#2803 alias precedent — with a model spec; the documented fallback is a dev-mode throw when tableName() receives an argument, also with a spec. Acceptance explicitly requires a spec, so this is propose-fix work rather than docs-only.

    Confidence: medium

    The report is clear and source-verified, but the acceptance criteria encode a design trade-off (alias overload vs. dev-mode throw) on a public framework API, so it can't be rated high.

    <!-- wheels-bot:triage:3079 -->
    <!-- wheels-bot:triage-class:bug -->
    <!-- wheels-bot:triage-confidence:medium -->

  2. wheels-bot commented on Jun 12, 2026

    @wheels-bot
    Contributor

    Wheels Bot — Fix proposed

    Draft PR: #3104

    Spec: vendor/wheels/tests/specs/model/miscellaneousSpec.cfc — failing → passing (pre-fix 894 passed, 2 failed; post-fix 896 passed, 0 failed on Lucee 7 + SQLite)
    Implementation: vendor/wheels/model/miscellaneous.cfc — tableName(name) now delegates to table() when given an argument and returns the resolved name; the zero-argument getter is unchanged.

    Scope note: this PR ships the framework (model + spec) half of the issue and lands as Refs, not Fixes. The six docs sites and CLAUDE.md:261 that teach the broken tableName("X") setter form are handled separately by bot-update-docs.yml, which runs after this PR opens. The issue stays open until the docs cleanup lands so its acceptance criteria (zero setter-style tableName(" call sites) can be verified.

    A human review is required before merge. The Reviewer will weigh in shortly.

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