| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
This was a problem in some places where numeric or character IDs needed to be changed, but Wheels was not putting the properties in the SET for the UPDATE to run.
|
Say you have a model, users, with a primary key of 'username' and an additional 'password' field. user = model("user").findByKey("dhumphreys");
user.update(username="dhumphreys2");The update will go through without error, but the 'username' primary key is not actually updated. The changed piece of code was keeping any properties that are part of the primary key from ever being updated. In some situations, such as when an auto incremented numeric id is used, this is appropriate. However, there are cases where some applications may need to update primary key values, especially in tables with composite keys. My change allows any property to be updated, as long as it has actually been changed in the model object. |
Sorry, something went wrong.
|
don, you're part of core now so you can commit this directly. I still think there are some areas with this patch that we need to consider such as security. rails doesn't allow you to update primary keys through direct access or mass assignment. personally i would like to have some sort of setting this feature to be turned on both globally and at the model level. |
Sorry, something went wrong.
|
Yes, I know I can commit directly. I just knew that this issue required some discussion, so I have not merged it yet. I also already had the changes in my own branch and saw no reason to put an extra feature branch in the main wheels repository. We could enable this with a setting pretty easily. It only really comes into play when not using an auto increment integer as primary key. |
Sorry, something went wrong.
|
looking at this again, i'm still thinking that this can cause quite a bit of havoc and security problems. including this patch would allow any primary key to be updated through mass assignment. the only way around that would be to use protectedProperties() and state the primary keys as protected properties on each model, which would be a pain. this still leaves the problem though of when you actually need to update a primary key. for that a work around is to use the updateAll() method which doesn't have the restrictions of using update(). |
Sorry, something went wrong.
TestBox silently skips bundles it cannot instantiate (e.g. CFML parse errors) — its JSON response shows totalPass: 0 with no failures and no errors, indistinguishable from "all clear" or "no specs found." The fresh-VM tutorial run lost ~10 minutes when an unescaped `#` inside a CSS selector crashed Lucee's parser silently. The user only discovered the broken spec by loading /wheels/app/tests in a browser. Add countSpecsOnDisk() and listSpecsOnDisk() helpers to TestRunner that walk the project's filesystem under variables.projectRoot and return *Spec.cfc counts/names as dotted bundle names. Wire them into Module.cfc::displayTestResults: if disk count exceeds TestBox's loaded bundle count, emit a "WARN N spec file(s) failed to compile and were silently skipped:" block listing the unloaded paths, and append "X failed to load" to the summary line. The exit code is unchanged — strict-loading mode is intentionally out of scope. The new code path is best-effort: any probe error is logged in verbose mode and never crashes the test report. Closes finding #2 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md (subsumes April 19 #15). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Records the four CLI fixes landed in batch B (gitkeep, migrate output, test runner compile-error surfacing, reload hint) and adds a Batch D shipped entry now that PR #2361 is merged. Marks #7 closed via the out-of-band PR #2360 (Rails-style argument order). Crosses out April 19's #15 ("test runner output format needs verification") which is subsumed by 2026-04-29 finding #2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(docs): add batch B plan for CLI output polish Plan covers findings #2, #3, #8, and a new sub-finding (.gitkeep files not copied by scaffolder) from the 2026-04-29 fresh-VM onboarding triage. Implementation lands in subsequent commits on this branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cli): copy .gitkeep files so empty test dirs survive git commit copyTemplateDir() previously skipped any file named .gitkeep with a comment that they "exist only to keep empty dirs in git" — but skipping them meant the scaffolded app's tests/specs/{controllers,functional, models}/ directories vanished on first git commit, contradicting the tutorial's chapter 1 file tree. Same problem hits app/lib, app/jobs, app/mailers, public/{files,images,javascripts,stylesheets}, and other intentionally-empty directories that ship with .gitkeep markers in the template tree (14 in total). Copy .gitkeep files byte-for-byte (no placeholder processing — they're empty by design). Extend NewCommandTemplateSpec to assert the .gitkeep files exist on disk for three representative paths. Note on test coverage: a deeper test that scaffolds via the production copyTemplateDir code path would require reflective invocation of a private method on Module.cfc; the existing template-existence check plus CI's full integration run cover the regression sufficiently. Closes the new sub-finding from docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md (top of the "Shipped" section, surfaced during batch A's Task 0 reconnaissance). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(migration): emit CRLF (not bare CR) so migrator output renders correctly Migrator.cfc and migrator/Base.cfc::announce() built their output using bare Chr(13). On macOS, Linux, and the LuCLI out() pipe, bare CR moves the cursor to column 0 without advancing the line, so subsequent text overwrites. On a fresh `wheels migrate latest`, the section header, divider, and per-table summary all collapsed onto a single line where the tutorial promised three. Switch every CR to CRLF (Chr(13) & Chr(10)) — 29 occurrences in Migrator.cfc plus the single line in migrator/Base.cfc::announce(). Add MigratorOutputSpec to pin the announce() contract so future migrator hacks can't drop the LF again. Update the existing "is appending announcements" assertion in migrationSpec.cfc that was previously asserting the buggy bare-CR concatenation. Closes finding #3 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cli): surface specs that fail to compile in wheels test output TestBox silently skips bundles it cannot instantiate (e.g. CFML parse errors) — its JSON response shows totalPass: 0 with no failures and no errors, indistinguishable from "all clear" or "no specs found." The fresh-VM tutorial run lost ~10 minutes when an unescaped `#` inside a CSS selector crashed Lucee's parser silently. The user only discovered the broken spec by loading /wheels/app/tests in a browser. Add countSpecsOnDisk() and listSpecsOnDisk() helpers to TestRunner that walk the project's filesystem under variables.projectRoot and return *Spec.cfc counts/names as dotted bundle names. Wire them into Module.cfc::displayTestResults: if disk count exceeds TestBox's loaded bundle count, emit a "WARN N spec file(s) failed to compile and were silently skipped:" block listing the unloaded paths, and append "X failed to load" to the summary line. The exit code is unchanged — strict-loading mode is intentionally out of scope. The new code path is best-effort: any probe error is logged in verbose mode and never crashes the test report. Closes finding #2 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md (subsumes April 19 #15). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cli): hint at cold reload from wheels reload output `wheels reload` re-fires the framework reload path (?reload=true) but does NOT re-run onApplicationStart — surprising to users coming from Rails or Django where restart is the default. Append a one-line cyan note pointing readers at `wheels stop && wheels start` whenever they need init code to re-execute. Pairs with the chapter 6 doc fix in batch A: the contract is now visible at both surfaces a fresh-VM user encounters (the auth tutorial and the CLI itself). Closes finding #8 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(docs): mark batch B + D items shipped, close April 19 #15 Records the four CLI fixes landed in batch B (gitkeep, migrate output, test runner compile-error surfacing, reload hint) and adds a Batch D shipped entry now that PR #2361 is merged. Marks #7 closed via the out-of-band PR #2360 (Rails-style argument order). Crosses out April 19's #15 ("test runner output format needs verification") which is subsumed by 2026-04-29 finding #2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundles 9 fixes uncovered by the 2026-04-30 fresh-VM tutorial bake. Each chapter is a focused edit; the bundle ships one PR / one CI run since they all live under web/sites/guides/. Chapter 1 (Hello, Wheels): - Drop `Controller.cfc` and `Model.cfc` from the "What got created" file tree — `wheels new` doesn't emit those base classes; the tree was aspirational. Add `rewrite.config` at the repo root, which IS emitted but wasn't listed. Finding #15. - Add a "First start downloads ~74 MB" Aside before the welcome-page step so a 30-second wait isn't a surprise. Finding #16. Chapter 2 (Your First Model): - Replace the made-up `Migration complete.` Expected output with the shape the runner actually emits today (`Migrating from 0 up to <ts>` + `Created table posts`), and note that the wording can drift across snapshots so readers verify on the `Created table` line. Finding #10. - Update the `t.timestamps()` description to mention all three columns it adds (`createdAt`, `updatedAt`, `deletedAt`) and link forward to Part 5's soft-delete callout. Previously claimed only two columns. Chapter 3 (CRUD Scaffold): - Rephrase the scaffold caution: it does NOT unconditionally append `.resources("posts")` to routes; it only appends when no resources line for the model exists. Chapter 2 already adds one, so the file is left alone. Finding #13. - Update the "generator emits findByKey(params.key) everywhere" claim — actually it uses `params.post` (route model binding) on key-scoped actions; only positional helpers fall back to `findByKey`. Finding #14. Chapter 4 (Validations + Turbo Frames): - Drop the manual `<label>` wrappers around helpers in `_form.cfm` and use the helpers' own `label="..."` argument instead. The previous shape produced nested `<label>` elements — exactly what chapter 3's caution about object-bound helpers warned against. Finding #11. Chapter 6 (Authentication, Part 6b): - Name `app/events/onapplicationstart.cfm` explicitly as the place to register the session strategy, and explain why `config/app.cfm` is the wrong place (`Application.cfc` this-scope, DI container not yet initialized). The previous "or equivalent on-init block" hedge cost the runner real time. Finding #6. - Recommend scraping `<meta name="csrf-token">` uniformly for curl smoke tests instead of mixing meta-tag-vs-form-input rules. Some forms (login raw inputs, comments, basecoat-rewritten views) don't always include the hidden input. Finding #7. - Replace the `--data-urlencode` recipe with a known-working raw `--data` form that pre-encodes brackets and `@`. The previous "use the `=` separator" advice was incomplete — Lucee's form parser treats any bracketed key as a nested-struct path regardless of encoding form. Finding #8. Findings deliberately not addressed in this PR: - #9 (soft-delete callout) — verified against current code: `t.timestamps()` emits all three columns including `deletedAt`, and `softDeleteProperty` defaults to `deletedAt`. Chapter 5's callout matches reality. The runner's snapshot-1660 observation likely predates the current behavior. - #12 (cosmetic migration drift) — aligning the docs to the generator's uglier emitted shape is value-negative; either source can drift again in a future release. - #17 (silent `brew tap`) — `exit 0` with no output is brew convention; adding a "no output expected" note is noise. - #19 (chapter 6 Compare table renders as wall) — markdown source is well-formed GFM; if the rendered output is broken it's a build/CSS issue not a source issue. Investigate in a follow-up if reproducible. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…flag (#2781) (#2802) * feat(migrator): t.references() columnNames alias + underscore suffix flag (#2781) `t.references()` has shipped since the 2017 dbmigrate merge with two quirks that bite anyone writing FK columns: the parameter is `referenceNames` (every sibling helper uses `columnNames` via `$combineArguments`), and the generated column suffix is `<x>id` (no underscore), breaking Wheels model `belongsTo` defaults which expect `<x>_id`. This PR resolves both quirks without changing default behavior for existing apps. ## Changes - **`t.references()` accepts `columnNames`** as an alias for `referenceNames` via `$combineArguments(combine="referenceNames,columnNames", required=true)`. Both keep working; `columnNames` is the modern form. - **New setting `useUnderscoreReferenceColumns`** governs the column suffix. Framework default: `false` (legacy `<x>id` preserved). New apps generated via `wheels new` get `set(useUnderscoreReferenceColumns=true)` pre-wired in `config/settings.cfm`. When true, both the FK column and the polymorphic `<x>type` companion become `<x>_id` / `<x>_type`. - **Scaffold template** flipped to `t.references(columnNames="vacation")` reflecting the modern convention. - **Conventions documented**: new `vendor/wheels/migrator/CLAUDE.md` formalizes the singular/plural alias pattern + the suffix flag. Anti-pattern #15 added to top-level CLAUDE.md so AI agents pick up the rule. Doc-block on `$combineArguments` expanded to position it as the framework's canonical alias convention with citations. ## Tests 5 new specs in `vendor/wheels/tests/specs/migrator/referencesSpec.cfc` covering alias acceptance, both flag states, and the polymorphic suffix path. Full suite: 3761 pass / 0 fail (was 3756 pre-PR). ## Scope Focused PR1 of a planned 4-PR series. Migration.cfc command-version consistency (`addReference`, `dropReference`, `removeColumn`, `addColumn`, `changeColumn`, `addForeignKey` argument aliases + suffix flag in those sites) lands in PR2 to keep this surface tight. `wheels upgrade check` advisory-tier and specific advisories for opt-in conventions follow in PR3 and PR4. Closes #2781 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * fix(migrator): address Reviewer A/B consensus findings (round 1) - Patch Migration.cfc::removeColumn(referenceName=) and addReference() to read $get("useUnderscoreReferenceColumns") so the wheels new template default (true) no longer produces wrong column names for these helpers - referencesSpec.cfc: correct file header to describe what the spec actually covers; sibling Migration.cfc DB-roundtrip coverage stays in migrationSpec.cfc - referencesSpec.cfc: add explicit useUnderscoreReferenceColumns=false reset to the alias describe block so test order can't false-fail it - referencesSpec.cfc: add direct backward-compat test asserting t.references(referenceNames="user") still produces the expected column - vendor/wheels/migrator/CLAUDE.md: drop the now-stale "lines 258, 278 hard-code & 'id'" anti-pattern note; both sites now route through $get - CHANGELOG.md [Unreleased] ### Added: document the columnNames alias and the useUnderscoreReferenceColumns setting (#2781) - web/sites/guides v4-0-0 + v4-0-1-snapshot migrations.mdx: document the columnNames argument as the preferred form, the legacy referenceNames back-compat, and the useUnderscoreReferenceColumns suffix flag Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> * test(migrator): address Reviewer A/B round-2 — addReference test coverage Round-1 left two gaps: 1. `referencesSpec.cfc` header claimed Migration.cfc DB-roundtrip coverage in migrationSpec.cfc that didn't actually exist. 2. `Migration.cfc::addReference()` was patched to read $get("useUnderscore ReferenceColumns") but had zero direct tests anywhere. This commit closes both. ## Changes - `vendor/wheels/tests/specs/migrator/migrationSpec.cfc`: new "Tests addReference" describe block with two DB-roundtrip tests (`creates a FK on <name>id when flag is false` and `creates a FK on <name>_id when flag is true`). Both follow the existing "Tests addForeignKey" pattern and skip on SQLite (which doesn't support altering CONSTRAINTS), so they run against MySQL/PG/MSSQL/H2 in CI. - `vendor/wheels/tests/specs/migrator/referencesSpec.cfc`: header rewritten to accurately describe coverage — addReference DB-roundtrip now correctly points at migrationSpec.cfc, removeColumn(referenceName=) is noted as having TableDefinition-layer coverage only (PR2 follow-up adds direct DB-roundtrip via migrationCommandsSpec.cfc). - `vendor/wheels/migrator/CLAUDE.md`: Tests section updated to match the new spec organization — explicit about which file covers what, why TableDefinition-layer tests are preferred for argument plumbing, and that FK-touching tests skip on SQLite. ## Verification - `bash tools/test-local.sh migrator` (Lucee 7 + SQLite): 224 pass, 0 fail, 6 skipped (the 4 existing FK-altering tests plus my 2 new ones on the same SQLite skip path). No regressions. - The new tests fire on every non-SQLite engine in CI. Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(migrator): add removeColumn(referenceName=) flag tests to close R2 coverage gap Round-2 follow-up commit. The bot's address-review described removeColumn(referenceName=) DB-roundtrip tests but didn't actually push them (my round-2 commit was already at HEAD). This commit makes the bot's address-review description retrospectively accurate and closes the coverage gap that finding 1 originally cited. ## Changes - `vendor/wheels/tests/specs/migrator/migrationSpec.cfc`: extend the existing "Tests removeColumn" describe block with two new it() blocks — one per flag state — that verify `removeColumn(referenceName=...)` computes the right column name to drop under both `useUnderscoreReferenceColumns=false` (legacy `<name>id`) and `=true` (modern `<name>_id`). These don't need the SQLite skip the addReference tests have because removeColumn just emits `ALTER TABLE DROP COLUMN`, which SQLite supports. - `vendor/wheels/tests/specs/migrator/referencesSpec.cfc`: header updated to drop the "no direct DB-roundtrip coverage yet" caveat for removeColumn(referenceName=) since that coverage now exists in migrationSpec.cfc. ## Verification - `bash tools/test-local.sh migrator`: 226 pass / 0 fail / 6 skipped (gained 2 from the new removeColumn tests; the addReference tests still skip on SQLite). - `bash tools/test-local.sh` (full): 3764 pass / 0 fail. No regressions. The new tests follow the same pattern as the existing "drops column from table" test in the same describe block. Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(migrator): save/restore useUnderscoreReferenceColumns in migrationSpec beforeAll/afterAll Reviewer A round-3 robustness note: the flag-true tests in migrationSpec.cfc reset the flag at the end of the test body, but if addReference() or $dbinfo() throws between the set and the cleanup, the dirty global leaks into every subsequent spec in the file. Mirror the existing migratorObjectCase pattern — snapshot the flag in beforeAll and restore it in afterAll. The in-test resets stay as belt-and-suspenders; afterAll is the safety net for the throw case. Reviewer A's second item (misleading header comment in referencesSpec) was already fixed in dd2963c (previous commit) — the header now just points at "Tests addReference" and "Tests removeColumn" describe blocks without overclaiming what the TableDefinition-layer tests cover. ## Verification - `bash tools/test-local.sh migrator`: 226 pass / 0 fail / 6 skipped. No regressions; the addReference and removeColumn tests still pass under the new save/restore contract. Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(migrator): capture removeColumn state before assert so cleanup always runs Reviewer A round-4 nit: the legacy and underscore removeColumn tests had a mid-test sanity expect() between createTable and dropTable. If the sanity assert fires, the test fails AND leaves the table in the database (next run recovers via force=true, but the dirty state is ugly). Refactor to the established addForeignKey / addReference pattern in the same file: capture before/after column lists, run cleanup, then do both asserts at the end. Cleanup is guaranteed regardless of which assert fails. Round-3 finding 1 (no beforeAll/afterAll save/restore for useUnderscoreReferenceColumns) was already fixed in 53034f9 — the reviewer was looking at dd2963c, one commit older. The in-test flag reset in the underscore test stays as belt-and-suspenders; the afterAll() guard added in 53034f9 is the safety net for an exception above that line. ## Verification - `bash tools/test-local.sh migrator`: 226 pass / 0 fail / 6 skipped. No regressions. The Reviewer B check failure on the prior SHA was a transient GitHub Actions auth error (HTTP 401: Bad credentials calling GraphQL), not a test or code failure. The new commit will trigger a fresh Reviewer B run. Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> --------- Signed-off-by: Peter Amiri <peter@alurium.com> Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
| Back | FazBrowse Home | New Git URL |
This was a problem in some places where numeric or character IDs needed to be changed, but Wheels was not putting the properties in the SET for the UPDATE to run.
Based on my findings, the hasChanged() call should be a sufficient check to decide whether or not to update any property value. The $addKeyWhereClause() function called from within $update() even considers that primary key values may have been changed. It doesn't make sense to not allow the model to send these changed values to the SQL server if the application required it.
This is reopening pull request #9, which I accidentally closed.