Skip to content

Commit c753c5e

Browse files
justin808claude
andcommitted
Add Pro-only feature validation for immediate_hydration and generated_component_packs_loading_strategy
Prevents non-Pro users from using these Pro-only features while maintaining backward compatibility for Pro users. Changes: - Add validate_pro_only_features method to detect Pro-only settings in non-Pro - In production: logs error without crashing - In non-production: raises ReactOnRails::Error with helpful message - Update validate_generated_component_packs_loading_strategy to skip auto-setting for non-Pro - Remove Pro-only settings from spec/dummy initializer - Add comprehensive unit tests for Pro-only validation - Update existing tests to stub ReactOnRailsPro for Pro feature tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 257214d commit c753c5e

File tree

3 files changed

+154
-7
lines changed

3 files changed

+154
-7
lines changed

lib/react_on_rails/configuration.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,43 @@ def setup_config_values
142142
check_component_registry_timeout
143143
validate_generated_component_packs_loading_strategy
144144
validate_enforce_private_server_bundles
145+
validate_pro_only_features
145146
end
146147

147148
private
148149

150+
def validate_pro_only_features
151+
return if defined?(ReactOnRailsPro)
152+
153+
pro_only_features = []
154+
155+
pro_only_features << "config.immediate_hydration = true" if immediate_hydration == true
156+
157+
if generated_component_packs_loading_strategy.present?
158+
pro_only_features << "config.generated_component_packs_loading_strategy = " \
159+
":#{generated_component_packs_loading_strategy}"
160+
end
161+
162+
return if pro_only_features.empty?
163+
164+
msg = <<~MSG
165+
**ERROR** ReactOnRails: You are using Pro-only features without React on Rails Pro:
166+
167+
#{pro_only_features.map { |f| " - #{f}" }.join("\n")}
168+
169+
These features are only available with a React on Rails Pro license.
170+
Please either:
171+
1. Remove these settings from your config/initializers/react_on_rails.rb
172+
2. Purchase a React on Rails Pro license at https://www.shakacode.com/react-on-rails-pro
173+
174+
For more information, see: https://www.shakacode.com/react-on-rails/docs/
175+
MSG
176+
177+
return Rails.logger.error(msg) if Rails.env.production?
178+
179+
raise ReactOnRails::Error, msg
180+
end
181+
149182
def check_component_registry_timeout
150183
self.component_registry_timeout = DEFAULT_COMPONENT_REGISTRY_TIMEOUT if component_registry_timeout.nil?
151184

@@ -176,6 +209,14 @@ def validate_generated_component_packs_loading_strategy
176209
1. Use :defer or :sync loading strategy instead of :async
177210
2. Upgrade to Shakapacker v8.2.0 or above to enable async script loading
178211
MSG
212+
213+
# Don't auto-set loading strategy for non-Pro users - this is a Pro-only feature
214+
# For Pro users, the setting will be auto-set in ReactOnRailsPro configuration
215+
if generated_component_packs_loading_strategy.nil? && !defined?(ReactOnRailsPro)
216+
# Leave as nil for non-Pro - the Pro validation will be skipped
217+
return
218+
end
219+
179220
if PackerUtils.supports_async_loading?
180221
self.generated_component_packs_loading_strategy ||= :async
181222
elsif generated_component_packs_loading_strategy.nil?

spec/dummy/config/initializers/react_on_rails.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,4 @@ def self.adjust_props_for_client_side_hydration(component_name, props)
4141
config.rendering_props_extension = RenderingPropsExtension
4242
config.components_subdirectory = "startup"
4343
config.auto_load_bundle = true
44-
config.immediate_hydration = false
45-
46-
# Use :defer to prevent race conditions with auto-generated component packs.
47-
# To test with :async (CI default), set: REACT_ON_RAILS_LOADING_STRATEGY=async
48-
# See: spec/dummy/TESTING_LOCALLY.md for reproducing CI failures
49-
loading_strategy = ENV.fetch("REACT_ON_RAILS_LOADING_STRATEGY", "defer").to_sym
50-
config.generated_component_packs_loading_strategy = loading_strategy
5144
end

spec/react_on_rails/configuration_spec.rb

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ module ReactOnRails
282282
before do
283283
allow(ReactOnRails::PackerUtils).to receive(:shakapacker_version_requirement_met?)
284284
.with("8.2.0").and_return(true)
285+
# Simulate Pro being available for these feature tests
286+
stub_const("ReactOnRailsPro", Module.new)
285287
end
286288

287289
it "defaults to :async" do
@@ -330,6 +332,8 @@ module ReactOnRails
330332
allow(ReactOnRails::PackerUtils).to receive(:shakapacker_version_requirement_met?)
331333
.with("8.2.0").and_return(false)
332334
allow(Rails.logger).to receive(:warn)
335+
# Simulate Pro being available for these feature tests
336+
stub_const("ReactOnRailsPro", Module.new)
333337
end
334338

335339
it "defaults to :sync and logs a warning" do
@@ -421,6 +425,115 @@ module ReactOnRails
421425
end
422426
end
423427
end
428+
429+
describe "Pro-only feature validation" do
430+
context "when ReactOnRailsPro is not defined" do
431+
before do
432+
# Ensure ReactOnRailsPro is not defined
433+
hide_const("ReactOnRailsPro") if defined?(ReactOnRailsPro)
434+
# Mock PackerUtils for generated_component_packs_loading_strategy
435+
allow(ReactOnRails::PackerUtils).to receive(:supports_async_loading?).and_return(true)
436+
end
437+
438+
context "when immediate_hydration is set to true" do
439+
it "raises error in non-production environments" do
440+
allow(Rails.env).to receive(:production?).and_return(false)
441+
expect do
442+
ReactOnRails.configure do |config|
443+
config.immediate_hydration = true
444+
end
445+
end.to raise_error(ReactOnRails::Error, /Pro-only features without React on Rails Pro/)
446+
end
447+
448+
it "logs error in production but does not raise" do
449+
allow(Rails.env).to receive(:production?).and_return(true)
450+
allow(Rails.logger).to receive(:error)
451+
expect do
452+
ReactOnRails.configure do |config|
453+
config.immediate_hydration = true
454+
end
455+
end.not_to raise_error
456+
expect(Rails.logger).to have_received(:error).with(/Pro-only features/)
457+
end
458+
end
459+
460+
context "when generated_component_packs_loading_strategy is explicitly set" do
461+
it "raises error in non-production environments" do
462+
allow(Rails.env).to receive(:production?).and_return(false)
463+
expect do
464+
ReactOnRails.configure do |config|
465+
config.generated_component_packs_loading_strategy = :async
466+
end
467+
end.to raise_error(ReactOnRails::Error, /Pro-only features without React on Rails Pro/)
468+
end
469+
470+
it "logs error in production but does not raise" do
471+
allow(Rails.env).to receive(:production?).and_return(true)
472+
allow(Rails.logger).to receive(:error)
473+
expect do
474+
ReactOnRails.configure do |config|
475+
config.generated_component_packs_loading_strategy = :defer
476+
end
477+
end.not_to raise_error
478+
expect(Rails.logger).to have_received(:error).with(/Pro-only features/)
479+
end
480+
end
481+
482+
context "when both Pro-only features are set" do
483+
it "lists both features in error message" do
484+
allow(Rails.env).to receive(:production?).and_return(false)
485+
expect do
486+
ReactOnRails.configure do |config|
487+
config.immediate_hydration = true
488+
config.generated_component_packs_loading_strategy = :async
489+
end
490+
end.to raise_error(ReactOnRails::Error, /immediate_hydration.*generated_component_packs_loading_strategy/m)
491+
end
492+
end
493+
494+
context "when immediate_hydration is set to false" do
495+
it "does not raise error" do
496+
expect do
497+
ReactOnRails.configure do |config|
498+
config.immediate_hydration = false
499+
end
500+
end.not_to raise_error
501+
end
502+
end
503+
504+
context "when no Pro-only features are set" do
505+
it "does not raise error" do
506+
expect do
507+
ReactOnRails.configure {} # rubocop:disable Lint/EmptyBlock
508+
end.not_to raise_error
509+
end
510+
end
511+
end
512+
513+
context "when ReactOnRailsPro is defined" do
514+
before do
515+
# Simulate ReactOnRailsPro being defined
516+
stub_const("ReactOnRailsPro", Module.new)
517+
allow(ReactOnRails::PackerUtils).to receive(:supports_async_loading?).and_return(true)
518+
end
519+
520+
it "allows immediate_hydration = true" do
521+
expect do
522+
ReactOnRails.configure do |config|
523+
config.immediate_hydration = true
524+
end
525+
end.not_to raise_error
526+
end
527+
528+
it "allows generated_component_packs_loading_strategy to be set" do
529+
expect do
530+
ReactOnRails.configure do |config|
531+
config.generated_component_packs_loading_strategy = :async
532+
end
533+
end.not_to raise_error
534+
end
535+
end
536+
end
424537
end
425538
end
426539

0 commit comments

Comments
 (0)