Auto-install react_on_rails_pro gem when --rsc/--pro flags are used#2439
Auto-install react_on_rails_pro gem when --rsc/--pro flags are used#2439
Conversation
When the install generator is run with --rsc or --pro, the Pro gem is now automatically added to the Gemfile via `bundle add react_on_rails_pro --strict`, similar to how Shakapacker is auto-installed. Previously, the generator would print an error message about the missing gem but continue creating Pro/RSC config files, leaving the app in a broken state where any subsequent Rails command would crash with NameError: uninitialized constant ReactOnRailsPro. Fixes #2436 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WalkthroughThis PR enhances the Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR adds automatic installation of the
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant InstallGenerator
participant ProSetup as ProSetup#missing_pro_gem?
participant GeneratorHelper as GeneratorHelper#pro_gem_installed?
participant Bundler
participant System as system("bundle add")
User->>InstallGenerator: rails g react_on_rails:install --pro
InstallGenerator->>ProSetup: missing_pro_gem?()
ProSetup->>GeneratorHelper: use_pro?()
GeneratorHelper-->>ProSetup: true
ProSetup->>GeneratorHelper: pro_gem_installed?()
GeneratorHelper-->>ProSetup: false
Note over ProSetup: NEW: Auto-install attempt
ProSetup->>Bundler: with_unbundled_env
Bundler->>System: bundle add react_on_rails_pro --strict
alt Install succeeds
System-->>Bundler: true
Bundler-->>ProSetup: true
ProSetup->>ProSetup: @pro_gem_installed = nil
ProSetup-->>InstallGenerator: false (gem not missing)
InstallGenerator->>InstallGenerator: Continue with setup_pro()
else Install fails
System-->>Bundler: false
Bundler-->>ProSetup: false
ProSetup->>ProSetup: GeneratorMessages.add_error(...)
ProSetup-->>InstallGenerator: true (gem is missing)
InstallGenerator->>User: Show error, abort
end
Last reviewed commit: 3d57fea |
| # Try auto-installing (similar to ensure_shakapacker_in_gemfile in install_generator) | ||
| puts Rainbow("📝 Adding react_on_rails_pro to Gemfile...").yellow | ||
| if Bundler.with_unbundled_env { system("bundle add react_on_rails_pro --strict") } | ||
| @pro_gem_installed = nil |
There was a problem hiding this comment.
Memoization invalidation is incorrect
Setting @pro_gem_installed = nil does not truly clear the memoization in pro_gem_installed? (defined in generator_helper.rb). The guard clause return @pro_gem_installed if defined?(@pro_gem_installed) checks defined?, which returns truthy even when the variable is nil. So subsequent calls to pro_gem_installed? would return nil (falsy), meaning the gem appears uninstalled even after a successful bundle add.
In practice this is low-risk because missing_pro_gem? is only called once per generator run, but the intent is clearly to allow re-detection. Use remove_instance_variable to fully clear the memo, or simply set it to true since the install just succeeded:
| @pro_gem_installed = nil | |
| remove_instance_variable(:@pro_gem_installed) if defined?(@pro_gem_installed) |
| puts Rainbow("📝 Adding react_on_rails_pro to Gemfile...").yellow | ||
| if Bundler.with_unbundled_env { system("bundle add react_on_rails_pro --strict") } | ||
| @pro_gem_installed = nil | ||
| return false | ||
| end |
There was a problem hiding this comment.
Existing tests will break — auto-install not stubbed and assertions outdated
Two issues with existing specs:
-
Tests will attempt a real
bundle addcall. The specs ininstall_generator_spec.rb(lines 1113-1138) andpro_generator_spec.rb(lines 31-46) stubGem.loaded_specsandgem_in_lockfile?but do not stubBundler.with_unbundled_env/system. Whenmissing_pro_gem?is called in tests, it will now attempt a realbundle add react_on_rails_pro --strictcommand, which will either fail (making the test pass accidentally by falling through to the error path) or hang/produce side effects in CI. -
install_generator_spec.rb:1124assertsexpect(error_text).to include("Try Pro free!"). This string was removed from the error message in this PR, so the test will fail.
These tests need to be updated to stub the auto-install attempt and remove the outdated assertion. For example:
before do
allow(Bundler).to receive(:with_unbundled_env).and_return(false)
endThere was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@react_on_rails/lib/generators/react_on_rails/pro_setup.rb`:
- Around line 58-60: The memoization reset is incorrect: in the block that runs
`bundle add react_on_rails_pro` (inside the `pro_gem_installed?` flow) remove
the memoized instance variable rather than assigning nil so subsequent calls
will re-evaluate; specifically, after a successful Bundler.with_unbundled_env
system call, call remove_instance_variable(:`@pro_gem_installed`) (or
alternatively set `@pro_gem_installed = true`) instead of `@pro_gem_installed =
nil` so the `defined?(`@pro_gem_installed`)` guard in `pro_gem_installed?` behaves
correctly.
| if Bundler.with_unbundled_env { system("bundle add react_on_rails_pro --strict") } | ||
| @pro_gem_installed = nil | ||
| return false |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's find and read the pro_setup.rb file to see the relevant code
fd "pro_setup.rb" --type fRepository: shakacode/react_on_rails
Length of output: 125
🏁 Script executed:
# Read the pro_setup.rb file to understand the context of lines 58-60
cat -n react_on_rails/lib/generators/react_on_rails/pro_setup.rb | head -100Repository: shakacode/react_on_rails
Length of output: 4504
🏁 Script executed:
# Also search for the pro_gem_installed? method definition
rg -n "def pro_gem_installed?" -A 5 --type rubyRepository: shakacode/react_on_rails
Length of output: 687
🏁 Script executed:
# And find the missing_pro_gem? method to understand the full context
rg -n "def missing_pro_gem?" -A 20 --type rubyRepository: shakacode/react_on_rails
Length of output: 2281
🏁 Script executed:
#!/bin/bash
# Find all callers of missing_pro_gem?
rg -n "missing_pro_gem?" --type ruby -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 7403
🏁 Script executed:
#!/bin/bash
# Also check what happens after missing_pro_gem? is called - look at the calling methods
rg -n "missing_pro_gem\?" -B 5 -A 5 --type rubyRepository: shakacode/react_on_rails
Length of output: 12125
🏁 Script executed:
#!/bin/bash
# Check the generator flow - see if pro_gem_installed? is called after missing_pro_gem? returns
rg -n "pro_gem_installed?" -B 3 -A 3 lib/generators/react_on_rails/install_generator.rbRepository: shakacode/react_on_rails
Length of output: 158
🏁 Script executed:
#!/bin/bash
# Check if pro_gem_installed? is called in the setup flow or initialization
rg -n "pro_gem_installed?" lib/generators/react_on_rails/ --type rubyRepository: shakacode/react_on_rails
Length of output: 138
🏁 Script executed:
#!/bin/bash
# Find the correct path for install_generator
find . -name "install_generator.rb" -type fRepository: shakacode/react_on_rails
Length of output: 135
🏁 Script executed:
#!/bin/bash
# Search for pro_gem_installed? calls in the codebase
rg -n "pro_gem_installed?" --type ruby -lRepository: shakacode/react_on_rails
Length of output: 190
🏁 Script executed:
#!/bin/bash
# Check all calls to pro_gem_installed? in the relevant files
rg -n "pro_gem_installed?" react_on_rails/lib/generators/react_on_rails/pro_setup.rb react_on_rails/lib/generators/react_on_rails/generator_helper.rb -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 2471
🏁 Script executed:
#!/bin/bash
# Check if install_generator has any references to pro_gem_installed? or missing_pro_gem?
rg -n "pro_gem_installed?|missing_pro_gem?" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 328
🏁 Script executed:
#!/bin/bash
# Check where installation_prerequisites_met? is called to understand generator flow
rg -n "installation_prerequisites_met?" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 3 -A 3Repository: shakacode/react_on_rails
Length of output: 855
🏁 Script executed:
#!/bin/bash
# Check if pro_setup is called and if it uses pro_gem_installed?
rg -n "setup_pro|include ProSetup" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 193
🏁 Script executed:
#!/bin/bash
# Look at the perform method to understand the full generator execution flow
grep -n "def perform" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -A 20Repository: shakacode/react_on_rails
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Check the invoke_generators method to see what happens after prerequisites are met
rg -n "def invoke_generators" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -A 15Repository: shakacode/react_on_rails
Length of output: 894
🏁 Script executed:
#!/bin/bash
# Check if any template or subsequent operation calls pro_gem_installed? after prerequisites check
rg -n "setup_pro" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Search for all calls to setup_pro in the entire generators directory
rg -n "setup_pro" ./react_on_rails/lib/generators/react_on_rails/ -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 1206
🏁 Script executed:
#!/bin/bash
# Check the base generator to see if it calls setup_pro
find ./react_on_rails/lib/generators -name "*.rb" -exec grep -l "setup_pro" {} \;Repository: shakacode/react_on_rails
Length of output: 191
🏁 Script executed:
#!/bin/bash
# Check the pro_generator prerequisites_met? method
rg -n "def prerequisites_met?" ./react_on_rails/lib/generators/react_on_rails/pro_generator.rb -A 5Repository: shakacode/react_on_rails
Length of output: 288
🏁 Script executed:
#!/bin/bash
# Check how pro_generator is invoked from install_generator
rg -n "invoke.*pro_generator\|:pro" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Search for invoke calls in install_generator that might trigger pro_generator
rg -n "invoke.*pro\|--pro" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 1 -A 1Repository: shakacode/react_on_rails
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Check base generator to see how it handles pro flag
rg -n "def perform|setup_pro\|--pro" ./react_on_rails/lib/generators/react_on_rails/base_generator.rb -B 2 -A 5Repository: shakacode/react_on_rails
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Find all generator files to understand the structure
find ./react_on_rails/lib/generators -name "*.rb" -type f | head -20Repository: shakacode/react_on_rails
Length of output: 1562
🏁 Script executed:
#!/bin/bash
# Search for how Pro is set up in the invoke flow
rg -n "options\[:pro\]|options\[:rsc\]" ./react_on_rails/lib/generators/react_on_rails/install_generator.rb -B 2 -A 2Repository: shakacode/react_on_rails
Length of output: 50
🏁 Script executed:
#!/bin/bash
# Search for pro flag handling in install_generator
cat -n ./react_on_rails/lib/generators/react_on_rails/install_generator.rb | grep -A 5 -B 5 "pro\|rsc" | head -100Repository: shakacode/react_on_rails
Length of output: 4833
🏁 Script executed:
#!/bin/bash
# Look at the base generator to see how it handles pro/rsc
cat -n ./react_on_rails/lib/generators/react_on_rails/base_generator.rb | head -150Repository: shakacode/react_on_rails
Length of output: 6916
🏁 Script executed:
#!/bin/bash
# Check test files to see if they reuse generator instances
rg -n "missing_pro_gem?" ./react_on_rails/spec/react_on_rails/generators/ -B 3 -A 5Repository: shakacode/react_on_rails
Length of output: 8195
Reset memoization correctly by removing the instance variable instead of setting it to nil.
After a successful bundle add react_on_rails_pro, the code sets @pro_gem_installed = nil to clear the memoization. However, pro_gem_installed? guards with return @pro_gem_installed if defined?(@pro_gem_installed). Since nil keeps the variable defined?, subsequent calls return nil rather than re-evaluating whether the gem is installed.
Proposed fix
if Bundler.with_unbundled_env { system("bundle add react_on_rails_pro --strict") }
- `@pro_gem_installed` = nil
+ remove_instance_variable(:`@pro_gem_installed`) if defined?(`@pro_gem_installed`)
return false
endAlternatively, set @pro_gem_installed = true since the bundle add succeeded.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if Bundler.with_unbundled_env { system("bundle add react_on_rails_pro --strict") } | |
| @pro_gem_installed = nil | |
| return false | |
| if Bundler.with_unbundled_env { system("bundle add react_on_rails_pro --strict") } | |
| remove_instance_variable(:`@pro_gem_installed`) if defined?(`@pro_gem_installed`) | |
| return false |
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@react_on_rails/lib/generators/react_on_rails/pro_setup.rb` around lines 58 -
60, The memoization reset is incorrect: in the block that runs `bundle add
react_on_rails_pro` (inside the `pro_gem_installed?` flow) remove the memoized
instance variable rather than assigning nil so subsequent calls will
re-evaluate; specifically, after a successful Bundler.with_unbundled_env system
call, call remove_instance_variable(:`@pro_gem_installed`) (or alternatively set
`@pro_gem_installed = true`) instead of `@pro_gem_installed = nil` so the
`defined?(`@pro_gem_installed`)` guard in `pro_gem_installed?` behaves correctly.
…ability (#2466) ## Summary LLMs consistently fail to generate correct React on Rails Pro setup code. After deep analysis ([#2465](#2465)), the root causes are: 1. **npm packages have no READMEs** — npm READMEs are the #1 training signal for LLMs 2. **No single quick-start page** — correct setup is spread across 4+ doc pages 3. **Incorrect example in Pro gem README** — uses old `@shakacode-tools/` scoped name and deprecated `bundlePath` This PR addresses the low-effort, high-impact recommendations from #2465. ### Changes - **Add README.md to all 3 npm packages** (`react-on-rails`, `react-on-rails-pro`, `react-on-rails-pro-node-renderer`) with correct API examples, config option tables, and package relationship docs - **Fix incorrect example in Pro gem README** — old scoped package name `@shakacode-tools/react-on-rails-pro-node-renderer` → `react-on-rails-pro-node-renderer`, deprecated `bundlePath` → `serverBundleCachePath` - **Add `docs/getting-started/pro-quick-start.md`** — single self-contained guide for Pro setup from scratch using the `--pro` generator - **Add `llms.txt`** at repo root — follows the [llms.txt convention](https://llmstxt.org/) providing LLMs with correct package relationships, API names, and config keys ### What this does NOT include - Generator changes (`--pro`/`--rsc`) — already merged in #2284 - Auto-install of `react_on_rails_pro` gem — open in #2439 ## Test plan - [ ] Verify npm README content is accurate against current API (TypeScript types in `packages/react-on-rails-pro-node-renderer/lib/`) - [ ] Verify Pro quick-start guide steps work with a fresh `rails new` + `rails generate react_on_rails:install --pro` - [ ] Verify `llms.txt` config examples match the generator templates in `lib/generators/react_on_rails/templates/pro/` - [ ] Confirm READMEs will be included in npm publish (no `files` field excluding them, or `files` field includes `README.md`) Closes #2465 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added a Pro quick-start guide with step‑by‑step setup, SSR verification, Server Components, configuration examples, troubleshooting, and next steps. * Added/expanded package READMEs and Node renderer documentation covering installation, configuration, usage, customization, and links. * Replaced private-repo and private-publishing references with public equivalents and clarified onboarding wording. * **Chores** * Included READMEs in the published file lists for two packages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
rails g react_on_rails:install --rsc(or--pro), the generator now automatically runsbundle add react_on_rails_pro --strictto install the Pro gemNameError: uninitialized constant ReactOnRailsPro)Test plan
rails g react_on_rails:install --rscon a fresh Rails app withoutreact_on_rails_proin Gemfilerails g react_on_rails:install --rsc --ignore-warningsto test the bypass pathFixes #2436
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Enhancements