Skip to content

Commit b9bd51a

Browse files
committed
Swap SKILL.md example to ActionController::TestRequest.new/create
Rails 4.2 → 5.0 case where `TestRequest.new` arity changes and `.create` is 5.0-only — each side raises on the other. Clearer two-sided example than `ignorable` → `ignored_columns=` (kept in references/code-patterns).
1 parent 3579c0b commit b9bd51a

6 files changed

Lines changed: 39 additions & 52 deletions

File tree

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,13 @@ In Claude Code, navigate to your Rails application directory and use natural lan
7171
When writing code that must work with two versions, always use `NextRails.next?`:
7272

7373
```ruby
74-
# app/models/project.rb
75-
class Project < ActiveRecord::Base
74+
# spec/requests/projects_spec.rb
75+
test_request =
7676
if NextRails.next?
77-
self.ignored_columns += [:category]
77+
ActionController::TestRequest.create
7878
else
79-
ignore_columns :category
79+
ActionController::TestRequest.new
8080
end
81-
end
8281
```
8382

8483
Never use `respond_to?`, `defined?`, or other feature-detection patterns. They are fragile, hard to clean up, and obscure intent.

dual-boot/CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Changelog
22

3-
## v1.1 — 22 April 2026
4-
- Replaced the `fixture_path`/`fixture_paths` and `serialize coder:` examples (both backwards-compat deprecations that don't require a conditional) with a genuine breaking change: `ignorable` gem's `ignore_columns` → native `ignored_columns=` at Rails 4.2 → 5.0, where each side's API raises `NoMethodError` on the other. (#2)
3+
## v1.1 — 24 April 2026
4+
- Swapped the canonical NextRails.next? example across the skill to `ActionController::TestRequest.new``TestRequest.create` at Rails 4.2 → 5.0: `new` takes optional `env` on 4.2 but requires 2 non-optional args on 5.0, and `create` doesn't exist on 4.2 — each side raises on the other. Updated SKILL.md, README.md, `references/code-patterns.md`, `workflows/cleanup-workflow.md`, and `examples/basic-setup.md`.
5+
- Previously replaced the `fixture_path`/`fixture_paths` and `serialize coder:` examples (both backwards-compat deprecations that don't require a conditional) with a genuine breaking change. (#2)
56
- Added a new "When NOT to Branch: Deprecations" section in `references/code-patterns.md` using `fixture_path``fixture_paths` as the counter-example, so readers learn that deprecations are unconditional migrations — not `NextRails.next?` conditionals.
67
- Broadened the "no feature detection" rule to call out `defined?` and `const_defined?` alongside `respond_to?`.
78
- Standardized on `NextRails.next?` polarity across the skill (removed the "`.current?` is also fine" clause from `CLAUDE.md`).

dual-boot/SKILL.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,25 @@ Reach for `NextRails.next?` only when the old and new APIs are genuinely **two-s
5050

5151
**WRONG — Do NOT use feature detection (`respond_to?`, `defined?`, etc.):**
5252
```ruby
53-
if Project.respond_to?(:ignored_columns=)
54-
self.ignored_columns += [:category]
55-
else
56-
ignore_columns :category
57-
end
53+
test_request =
54+
if ActionController::TestRequest.respond_to?(:create)
55+
ActionController::TestRequest.create
56+
else
57+
ActionController::TestRequest.new
58+
end
5859
```
5960

6061
**CORRECT — Use `NextRails.next?`:**
6162
```ruby
62-
# app/models/project.rb
63-
class Project < ActiveRecord::Base
63+
test_request =
6464
if NextRails.next?
65-
self.ignored_columns += [:category]
65+
ActionController::TestRequest.create
6666
else
67-
ignore_columns :category
67+
ActionController::TestRequest.new
6868
end
69-
end
7069
```
7170

72-
This is a genuine two-sided case (Rails 4.2 → 5.0): on 4.2 the app uses the [`ignorable`](https://github.com/nthj/ignorable) gem's `ignore_columns` class method. Rails 5.0 introduced native `ignored_columns=` with different syntax, and once the gem is dropped on the 5.0 side, `ignore_columns` raises `NoMethodError`. `ignored_columns=` raises `NoMethodError` on 4.2 where it doesn't yet exist.
71+
This is a genuine two-sided case (Rails 4.2 → 5.0). On 4.2, [`ActionController::TestRequest.new`](https://github.com/rails/rails/blob/11f2bdf75a888682b34df0f9be03b94f54fc6796/actionpack/lib/action_controller/test_case.rb#L201) takes an optional `env`; on 5.0 `new` [requires two non-optional arguments](https://github.com/rails/rails/blob/c4d3e202e10ae627b3b9c34498afb45450652421/actionpack/lib/action_controller/test_case.rb#L48) so the 4.2 call fails. Rails 5.0 introduces `TestRequest.create`, which does not exist on 4.2 — so each side raises on the other.
7372

7473
Put the next-version branch on top so cleanup is mechanical: after the upgrade, keep the `if` body and drop the `else`. See `references/code-patterns.md` for more examples.
7574

dual-boot/examples/basic-setup.md

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ next_rails --init
2626

2727
### 3. Configure Gemfile
2828

29-
If your 4.2 app already depends on a gem that needs dropping on the 5.0 side (the `ignorable` gem in this example), move it from the Gemfile root into the `else` branch so it's installed only for Rails 4.2.
30-
3129
```ruby
3230
# Gemfile
3331

@@ -41,7 +39,6 @@ if next?
4139
gem 'rails', '~> 5.0.0'
4240
else
4341
gem 'rails', '~> 4.2.0'
44-
gem 'ignorable' # used for `ignore_columns` on 4.2; dropped on 5.0
4542
end
4643

4744
gem 'next_rails'
@@ -72,17 +69,16 @@ BUNDLE_GEMFILE=Gemfile.next bundle exec rspec
7269

7370
### 6. Fix a Breaking Change
7471

75-
Rails 5.0 introduced a native `ignored_columns=` setter, replacing the `ignorable` gem's `ignore_columns` class method. With the gem dropped on the 5.0 side, `ignore_columns` raises `NoMethodError` there; `ignored_columns=` raises `NoMethodError` on 4.2 where it doesn't yet exist. A conditional is required:
72+
On Rails 4.2, `ActionController::TestRequest.new` takes an optional `env`. On 5.0, `new` requires two non-optional arguments (so the 4.2 call raises `ArgumentError`), and 5.0 introduces `TestRequest.create` — which doesn't exist on 4.2 (`NoMethodError`). Each side raises on the other. A conditional is required:
7673

7774
```ruby
78-
# app/models/project.rb
79-
class Project < ActiveRecord::Base
75+
# spec/requests/projects_spec.rb
76+
test_request =
8077
if NextRails.next?
81-
self.ignored_columns += [:category]
78+
ActionController::TestRequest.create
8279
else
83-
ignore_columns :category
80+
ActionController::TestRequest.new
8481
end
85-
end
8682
```
8783

8884
### 7. Verify Both Pass
@@ -95,7 +91,7 @@ BUNDLE_GEMFILE=Gemfile.next bundle exec rspec # Next: green
9591
### 8. Commit
9692

9793
```bash
98-
git add Gemfile Gemfile.next Gemfile.next.lock app/models/project.rb
94+
git add Gemfile Gemfile.next Gemfile.next.lock spec/requests/projects_spec.rb
9995
git commit -m "Set up dual-boot for Rails 4.2 → 5.0 upgrade"
10096
```
10197

@@ -106,19 +102,16 @@ git commit -m "Set up dual-boot for Rails 4.2 → 5.0 upgrade"
106102
Once you're fully on Rails 5.0, clean up:
107103

108104
```ruby
109-
# app/models/project.rb — BEFORE cleanup
110-
class Project < ActiveRecord::Base
105+
# spec/requests/projects_spec.rb — BEFORE cleanup
106+
test_request =
111107
if NextRails.next?
112-
self.ignored_columns += [:category]
108+
ActionController::TestRequest.create
113109
else
114-
ignore_columns :category
110+
ActionController::TestRequest.new
115111
end
116-
end
117112

118-
# app/models/project.rb — AFTER cleanup
119-
class Project < ActiveRecord::Base
120-
self.ignored_columns += [:category]
121-
end
113+
# spec/requests/projects_spec.rb — AFTER cleanup
114+
test_request = ActionController::TestRequest.create
122115
```
123116

124117
See `workflows/cleanup-workflow.md` for the full cleanup process.

dual-boot/references/code-patterns.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,23 @@ Use `NextRails.next?` anywhere your application code must behave differently bet
66

77
**Only branch when the old code actually breaks on the next version.** A deprecation warning is not a reason for a conditional — if the new API works on both, replace the call site directly and let the deprecation disappear on its own. Reserve `NextRails.next?` for removed constants, removed methods, or incompatible signature/return-type changes that would raise an error otherwise.
88

9-
The version numbers in the example below are from a Rails 4.2 → 5.0 upgrade, but the pattern applies any time a gem-provided API is replaced by a native Rails API with different syntax (or vice versa) — the same shape works for any adjacent-version boundary where dropping the gem on one side makes the call unavailable.
9+
The version numbers in the example below are from a Rails 4.2 → 5.0 upgrade, but the pattern applies any time a method's signature or availability changes incompatibly across versions — the same shape works for any adjacent-version boundary where each side raises on the other's call.
1010

1111
---
1212

1313
## Rails API Changes Requiring a Conditional
1414

15-
### `ignorable` gem → native `ignored_columns=` (Rails 4.2 → 5.0)
15+
### `ActionController::TestRequest.new``.create` (Rails 4.2 → 5.0)
1616

17-
An app using the [`ignorable`](https://github.com/nthj/ignorable) gem to ignore columns on Rails 4.2 hits a genuine two-sided case when upgrading to 5.0, which introduced a native `ignored_columns=` with different syntax. If the gem is dropped on the 5.0 side (since Rails now has the feature), `ignore_columns :category` raises `NoMethodError` there; `self.ignored_columns += [:category]` raises `NoMethodError` on 4.2 where the setter doesn't exist yet.
17+
On Rails 4.2, [`ActionController::TestRequest.new`](https://github.com/rails/rails/blob/11f2bdf75a888682b34df0f9be03b94f54fc6796/actionpack/lib/action_controller/test_case.rb#L201) takes an optional `env` argument. On Rails 5.0, `new` [requires two non-optional arguments](https://github.com/rails/rails/blob/c4d3e202e10ae627b3b9c34498afb45450652421/actionpack/lib/action_controller/test_case.rb#L48), so the 4.2-style call raises `ArgumentError`. Rails 5.0 introduced `TestRequest.create` to hide that complexity — but `.create` does not exist on 4.2 (`NoMethodError`). Each side raises on the other's call.
1818

1919
```ruby
20-
# app/models/project.rb
21-
class Project < ActiveRecord::Base
20+
test_request =
2221
if NextRails.next?
23-
self.ignored_columns += [:category]
22+
ActionController::TestRequest.create
2423
else
25-
ignore_columns :category
24+
ActionController::TestRequest.new
2625
end
27-
end
2826
```
2927

3028
---

dual-boot/workflows/cleanup-workflow.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,17 @@ For each file found in Step 1, keep only the `NextRails.next?` (true) branch and
2828

2929
### Before:
3030
```ruby
31-
class Project < ActiveRecord::Base
31+
test_request =
3232
if NextRails.next?
33-
self.ignored_columns += [:category]
33+
ActionController::TestRequest.create
3434
else
35-
ignore_columns :category
35+
ActionController::TestRequest.new
3636
end
37-
end
3837
```
3938

4039
### After:
4140
```ruby
42-
class Project < ActiveRecord::Base
43-
self.ignored_columns += [:category]
44-
end
41+
test_request = ActionController::TestRequest.create
4542
```
4643

4744
---

0 commit comments

Comments
 (0)