From 68410acc272e0b3b824eaf7dabde1879c4a4e3c0 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Sat, 2 Nov 2024 13:40:17 +0300 Subject: [PATCH 1/8] Drop leftover require --- lib/inertia_rails/inertia_rails.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/inertia_rails/inertia_rails.rb b/lib/inertia_rails/inertia_rails.rb index c533a0f..7b1b320 100644 --- a/lib/inertia_rails/inertia_rails.rb +++ b/lib/inertia_rails/inertia_rails.rb @@ -1,5 +1,3 @@ -# Needed for `thread_mattr_accessor` -require 'active_support/core_ext/module/attribute_accessors_per_thread' require 'inertia_rails/lazy' require 'inertia_rails/configuration' From d98e8170a7236b2df983744ee0c86a7b96a0d684 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Sat, 2 Nov 2024 13:46:01 +0300 Subject: [PATCH 2/8] Do not wrap simple values in procs --- lib/inertia_rails/lazy.rb | 24 ++++------- lib/inertia_rails/renderer.rb | 20 +++++---- .../app/controllers/application_controller.rb | 3 ++ spec/inertia/lazy_spec.rb | 42 +++++++++++++++---- 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/lib/inertia_rails/lazy.rb b/lib/inertia_rails/lazy.rb index 7f26a6a..3b3ed2d 100644 --- a/lib/inertia_rails/lazy.rb +++ b/lib/inertia_rails/lazy.rb @@ -1,28 +1,20 @@ +# frozen_string_literal: true + module InertiaRails class Lazy def initialize(value = nil, &block) + raise ArgumentError, 'You must provide either a value or a block, not both' if value && block + @value = value @block = block end - def call - to_proc.call + def call(controller) + value.respond_to?(:call) ? controller.instance_exec(&value) : value end - def to_proc - # This is called by controller.instance_exec, which changes self to the - # controller instance. That makes the instance variables unavailable to the - # proc via closure. Copying the instance variables to local variables before - # the proc is returned keeps them in scope for the returned proc. - value = @value - block = @block - if value.respond_to?(:call) - value - elsif value - Proc.new { value } - else - block - end + def value + @value.nil? ? @block : @value end end end diff --git a/lib/inertia_rails/renderer.rb b/lib/inertia_rails/renderer.rb index ec090c2..ee1fa99 100644 --- a/lib/inertia_rails/renderer.rb +++ b/lib/inertia_rails/renderer.rb @@ -76,12 +76,16 @@ def computed_props end end - deep_transform_values( - _props, - lambda do |prop| - prop.respond_to?(:call) ? controller.instance_exec(&prop) : prop + deep_transform_values _props do |prop| + case prop + when Lazy + prop.call(controller) + when Proc + controller.instance_exec(&prop) + else + prop end - ) + end end def page @@ -93,10 +97,10 @@ def page } end - def deep_transform_values(hash, proc) - return proc.call(hash) unless hash.is_a? Hash + def deep_transform_values(hash, &block) + return block.call(hash) unless hash.is_a? Hash - hash.transform_values {|value| deep_transform_values(value, proc)} + hash.transform_values {|value| deep_transform_values(value, &block)} end def partial_keys diff --git a/spec/dummy/app/controllers/application_controller.rb b/spec/dummy/app/controllers/application_controller.rb index 09705d1..ebd7242 100644 --- a/spec/dummy/app/controllers/application_controller.rb +++ b/spec/dummy/app/controllers/application_controller.rb @@ -1,2 +1,5 @@ class ApplicationController < ActionController::Base + def controller_method + 'controller_method value' + end end diff --git a/spec/inertia/lazy_spec.rb b/spec/inertia/lazy_spec.rb index 4fe213d..ae982fa 100644 --- a/spec/inertia/lazy_spec.rb +++ b/spec/inertia/lazy_spec.rb @@ -1,20 +1,44 @@ RSpec.describe InertiaRails::Lazy do describe '#call' do - context 'with a value' do - it 'returns the value' do - expect(InertiaRails::Lazy.new('thing').call).to eq('thing') - end - end + subject(:call) { prop.call(controller) } + let(:prop) { described_class.new('value') } + let(:controller) { ApplicationController.new } + + it { is_expected.to eq('value') } context 'with a callable value' do - it 'returns the result of the callable value' do - expect(InertiaRails::Lazy.new(->{ 'thing' }).call).to eq('thing') + let(:prop) { described_class.new(-> { 'callable' }) } + + it { is_expected.to eq('callable') } + + context "with false as value" do + let(:prop) { described_class.new(false) } + + it { is_expected.to eq(false) } + end + + context "with nil as value" do + let(:prop) { described_class.new(nil) } + + it { is_expected.to eq(nil) } + end + + context "with dependency on the context of a controller" do + let(:prop) { described_class.new(-> { controller_method }) } + + it { is_expected.to eq('controller_method value') } end end context 'with a block' do - it 'returns the result of the block' do - expect(InertiaRails::Lazy.new{'thing'}.call).to eq('thing') + let(:prop) { described_class.new { 'block' } } + + it { is_expected.to eq('block') } + + context "with dependency on the context of a controller" do + let(:prop) { described_class.new { controller_method } } + + it { is_expected.to eq('controller_method value') } end end end From 3302b2548b76cfb63c91e6d05241d3c47a42e67c Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Sat, 2 Nov 2024 16:56:47 +0300 Subject: [PATCH 3/8] Introduce InertiaRails.always --- lib/inertia_rails/always_prop.rb | 6 ++++ lib/inertia_rails/{lazy.rb => base_prop.rb} | 3 +- lib/inertia_rails/inertia_rails.rb | 28 +++++++++++------ lib/inertia_rails/lazy_prop.rb | 6 ++++ lib/inertia_rails/renderer.rb | 8 +++-- .../inertia_render_test_controller.rb | 28 +++++++++++++++++ spec/dummy/config/routes.rb | 2 ++ spec/inertia/always_prop_spec.rb | 3 ++ spec/inertia/base_prop_spec.rb | 3 ++ spec/inertia/lazy_prop_spec.rb | 3 ++ spec/inertia/rendering_spec.rb | 31 ++++++++++++++++--- spec/rails_helper.rb | 3 +- .../shared_examples.rb} | 28 ++++++++--------- 13 files changed, 117 insertions(+), 35 deletions(-) create mode 100644 lib/inertia_rails/always_prop.rb rename lib/inertia_rails/{lazy.rb => base_prop.rb} (89%) create mode 100644 lib/inertia_rails/lazy_prop.rb create mode 100644 spec/inertia/always_prop_spec.rb create mode 100644 spec/inertia/base_prop_spec.rb create mode 100644 spec/inertia/lazy_prop_spec.rb rename spec/{inertia/lazy_spec.rb => support/shared_examples.rb} (64%) diff --git a/lib/inertia_rails/always_prop.rb b/lib/inertia_rails/always_prop.rb new file mode 100644 index 0000000..c52f9d7 --- /dev/null +++ b/lib/inertia_rails/always_prop.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module InertiaRails + class AlwaysProp < BaseProp + end +end diff --git a/lib/inertia_rails/lazy.rb b/lib/inertia_rails/base_prop.rb similarity index 89% rename from lib/inertia_rails/lazy.rb rename to lib/inertia_rails/base_prop.rb index 3b3ed2d..82e8c3c 100644 --- a/lib/inertia_rails/lazy.rb +++ b/lib/inertia_rails/base_prop.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true module InertiaRails - class Lazy + # Base class for all props. + class BaseProp def initialize(value = nil, &block) raise ArgumentError, 'You must provide either a value or a block, not both' if value && block diff --git a/lib/inertia_rails/inertia_rails.rb b/lib/inertia_rails/inertia_rails.rb index 7b1b320..2c1d8b7 100644 --- a/lib/inertia_rails/inertia_rails.rb +++ b/lib/inertia_rails/inertia_rails.rb @@ -1,18 +1,26 @@ -require 'inertia_rails/lazy' +require 'inertia_rails/base_prop' +require 'inertia_rails/always_prop' +require 'inertia_rails/lazy_prop' require 'inertia_rails/configuration' module InertiaRails - CONFIGURATION = Configuration.default + class << self + CONFIGURATION = Configuration.default - def self.configure - yield(CONFIGURATION) - end + def configure + yield(CONFIGURATION) + end - def self.configuration - CONFIGURATION - end + def configuration + CONFIGURATION + end + + def lazy(value = nil, &block) + LazyProp.new(value, &block) + end - def self.lazy(value = nil, &block) - InertiaRails::Lazy.new(value, &block) + def always(value = nil, &block) + AlwaysProp.new(value, &block) + end end end diff --git a/lib/inertia_rails/lazy_prop.rb b/lib/inertia_rails/lazy_prop.rb new file mode 100644 index 0000000..6d24727 --- /dev/null +++ b/lib/inertia_rails/lazy_prop.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module InertiaRails + class LazyProp < BaseProp + end +end diff --git a/lib/inertia_rails/renderer.rb b/lib/inertia_rails/renderer.rb index ee1fa99..f16505d 100644 --- a/lib/inertia_rails/renderer.rb +++ b/lib/inertia_rails/renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'net/http' require 'json' require_relative "inertia_rails" @@ -70,15 +72,15 @@ def merge_props(shared_data, props) def computed_props _props = merge_props(shared_data, props).select do |key, prop| if rendering_partial_component? - key.in? partial_keys + key.in?(partial_keys) || prop.is_a?(AlwaysProp) else - !prop.is_a?(InertiaRails::Lazy) + !prop.is_a?(LazyProp) end end deep_transform_values _props do |prop| case prop - when Lazy + when BaseProp prop.call(controller) when Proc controller.instance_exec(&prop) diff --git a/spec/dummy/app/controllers/inertia_render_test_controller.rb b/spec/dummy/app/controllers/inertia_render_test_controller.rb index 52d2b93..c844816 100644 --- a/spec/dummy/app/controllers/inertia_render_test_controller.rb +++ b/spec/dummy/app/controllers/inertia_render_test_controller.rb @@ -7,6 +7,23 @@ def props } end + def except_props + render inertia: 'TestComponent', props: { + flat: 'flat param', + lazy: InertiaRails.lazy('lazy param'), + nested_lazy: InertiaRails.lazy do + { + first: 'first nested lazy param', + } + end, + nested: { + first: 'first nested param', + second: 'second nested param' + }, + always: InertiaRails.always('always prop') + } + end + def view_data render inertia: 'TestComponent', view_data: { name: 'Brian', @@ -34,4 +51,15 @@ def lazy_props grit: InertiaRails.lazy(->{ 'intense' }) } end + + def always_props + render inertia: 'TestComponent', props: { + always: InertiaRails.always('always prop'), + regular: 'regular prop', + lazy: InertiaRails.lazy do + 'lazy prop' + end, + another_lazy: InertiaRails.lazy(->{ 'another lazy prop' }) + } + end end diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb index f6347c2..451fb2a 100644 --- a/spec/dummy/config/routes.rb +++ b/spec/dummy/config/routes.rb @@ -30,6 +30,8 @@ get 'error_500' => 'inertia_test#error_500' get 'content_type_test' => 'inertia_test#content_type_test' get 'lazy_props' => 'inertia_render_test#lazy_props' + get 'always_props' => 'inertia_render_test#always_props' + get 'except_props' => 'inertia_render_test#except_props' get 'non_inertiafied' => 'inertia_test#non_inertiafied' get 'instance_props_test' => 'inertia_rails_mimic#instance_props_test' diff --git a/spec/inertia/always_prop_spec.rb b/spec/inertia/always_prop_spec.rb new file mode 100644 index 0000000..62b820b --- /dev/null +++ b/spec/inertia/always_prop_spec.rb @@ -0,0 +1,3 @@ +RSpec.describe InertiaRails::AlwaysProp do + it_behaves_like 'base prop' +end diff --git a/spec/inertia/base_prop_spec.rb b/spec/inertia/base_prop_spec.rb new file mode 100644 index 0000000..079f552 --- /dev/null +++ b/spec/inertia/base_prop_spec.rb @@ -0,0 +1,3 @@ +RSpec.describe InertiaRails::BaseProp do + it_behaves_like 'base prop' +end diff --git a/spec/inertia/lazy_prop_spec.rb b/spec/inertia/lazy_prop_spec.rb new file mode 100644 index 0000000..7f154eb --- /dev/null +++ b/spec/inertia/lazy_prop_spec.rb @@ -0,0 +1,3 @@ +RSpec.describe InertiaRails::LazyProp do + it_behaves_like 'base prop' +end diff --git a/spec/inertia/rendering_spec.rb b/spec/inertia/rendering_spec.rb index 6f15443..e9d9b0f 100644 --- a/spec/inertia/rendering_spec.rb +++ b/spec/inertia/rendering_spec.rb @@ -68,7 +68,6 @@ it { is_expected.to eq page.to_json } - it 'has the proper headers' do expect(response.headers['X-Inertia']).to eq 'true' expect(response.headers['Vary']).to eq 'X-Inertia' @@ -76,7 +75,7 @@ end it 'has the proper body' do - expect(JSON.parse(response.body)).to include('url' => '/props') + expect(response.parsed_body).to include('url' => '/props') end it 'has the proper status code' do @@ -85,7 +84,7 @@ end context 'partial rendering' do - let (:page) { + let(:page) { InertiaRails::Renderer.new('TestComponent', controller, request, response, '', props: { sport: 'hockey' }).send(:page) } let(:headers) {{ @@ -116,7 +115,7 @@ context 'lazy prop rendering' do context 'on first load' do - let (:page) { + let(:page) { InertiaRails::Renderer.new('TestComponent', controller, request, response, '', props: { name: 'Brian'}).send(:page) } before { get lazy_props_path } @@ -125,7 +124,7 @@ end context 'with a partial reload' do - let (:page) { + let(:page) { InertiaRails::Renderer.new('TestComponent', controller, request, response, '', props: { sport: 'basketball', level: 'worse than he believes', grit: 'intense'}).send(:page) } let(:headers) {{ @@ -142,6 +141,28 @@ it { is_expected.not_to include('intense') } end end + + context 'always prop rendering' do + let(:headers) { { 'X-Inertia' => true } } + + before { get always_props_path, headers: headers } + + it "returns non-optional props on first load" do + expect(response.parsed_body["props"]).to eq({"always" => 'always prop', "regular" => 'regular prop' }) + end + + context 'with a partial reload' do + let(:headers) {{ + 'X-Inertia' => true, + 'X-Inertia-Partial-Data' => 'lazy', + 'X-Inertia-Partial-Component' => 'TestComponent', + }} + + it "returns listed and always props" do + expect(response.parsed_body["props"]).to eq({"always" => 'always prop', "lazy" => 'lazy prop' }) + end + end + end end def inertia_div(page) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index f89646e..2843743 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -10,9 +10,8 @@ abort("The Rails environment is running in production mode!") if Rails.env.production? require 'rspec/rails' # Require the spec/support directory and its subdirectories. -Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } +Dir[Pathname.new(__dir__).join('support', '**', '*.rb')].each { |f| require f } -require_relative './support/helper_module' # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are diff --git a/spec/inertia/lazy_spec.rb b/spec/support/shared_examples.rb similarity index 64% rename from spec/inertia/lazy_spec.rb rename to spec/support/shared_examples.rb index ae982fa..75c921e 100644 --- a/spec/inertia/lazy_spec.rb +++ b/spec/support/shared_examples.rb @@ -1,4 +1,4 @@ -RSpec.describe InertiaRails::Lazy do +RSpec.shared_examples 'base prop' do describe '#call' do subject(:call) { prop.call(controller) } let(:prop) { described_class.new('value') } @@ -6,24 +6,24 @@ it { is_expected.to eq('value') } - context 'with a callable value' do - let(:prop) { described_class.new(-> { 'callable' }) } + context 'with false as value' do + let(:prop) { described_class.new(false) } - it { is_expected.to eq('callable') } + it { is_expected.to eq(false) } + end - context "with false as value" do - let(:prop) { described_class.new(false) } + context 'with nil as value' do + let(:prop) { described_class.new(nil) } - it { is_expected.to eq(false) } - end + it { is_expected.to eq(nil) } + end - context "with nil as value" do - let(:prop) { described_class.new(nil) } + context 'with a callable value' do + let(:prop) { described_class.new(-> { 'callable' }) } - it { is_expected.to eq(nil) } - end + it { is_expected.to eq('callable') } - context "with dependency on the context of a controller" do + context 'with dependency on the context of a controller' do let(:prop) { described_class.new(-> { controller_method }) } it { is_expected.to eq('controller_method value') } @@ -35,7 +35,7 @@ it { is_expected.to eq('block') } - context "with dependency on the context of a controller" do + context 'with dependency on the context of a controller' do let(:prop) { described_class.new { controller_method } } it { is_expected.to eq('controller_method value') } From 6ea58797bc076adaa5c136cec9d535144774fa18 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Sat, 2 Nov 2024 17:02:48 +0300 Subject: [PATCH 4/8] Introduce except props support --- lib/inertia_rails/renderer.rb | 16 ++++++++ spec/inertia/rendering_spec.rb | 73 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/lib/inertia_rails/renderer.rb b/lib/inertia_rails/renderer.rb index f16505d..b1a0db1 100644 --- a/lib/inertia_rails/renderer.rb +++ b/lib/inertia_rails/renderer.rb @@ -78,6 +78,8 @@ def computed_props end end + drop_partial_except_keys(_props) if rendering_partial_component? + deep_transform_values _props do |prop| case prop when BaseProp @@ -105,10 +107,24 @@ def deep_transform_values(hash, &block) hash.transform_values {|value| deep_transform_values(value, &block)} end + def drop_partial_except_keys(hash) + partial_except_keys.each do |key| + parts = key.to_s.split('.').map(&:to_sym) + *initial_keys, last_key = parts + current = initial_keys.any? ? hash.dig(*initial_keys) : hash + + current.delete(last_key) if current.is_a?(Hash) && !current[last_key].is_a?(AlwaysProp) + end + end + def partial_keys (@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact.map(&:to_sym) end + def partial_except_keys + (@request.headers['X-Inertia-Partial-Except'] || '').split(',').filter_map(&:to_sym) + end + def rendering_partial_component? @request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component end diff --git a/spec/inertia/rendering_spec.rb b/spec/inertia/rendering_spec.rb index e9d9b0f..509acbb 100644 --- a/spec/inertia/rendering_spec.rb +++ b/spec/inertia/rendering_spec.rb @@ -113,6 +113,79 @@ end end + context 'partial except rendering' do + let(:headers) do + { + 'X-Inertia' => true, + 'X-Inertia-Partial-Data' => 'nested,nested_lazy', + 'X-Inertia-Partial-Except' => 'nested', + 'X-Inertia-Partial-Component' => 'TestComponent', + } + end + + before { get except_props_path, headers: headers } + + it 'returns listed props without excepted' do + expect(response.parsed_body['props']).to eq( + 'always' => 'always prop', + 'nested_lazy' => { 'first' => 'first nested lazy param' }, + ) + end + + context 'when except always prop' do + let(:headers) {{ + 'X-Inertia' => true, + 'X-Inertia-Partial-Data' => 'nested_lazy', + 'X-Inertia-Partial-Except' => 'always_prop', + 'X-Inertia-Partial-Component' => 'TestComponent', + }} + + it 'returns always prop anyway' do + expect(response.parsed_body['props']).to eq( + 'always' => 'always prop', + 'nested_lazy' => { 'first' => 'first nested lazy param' }, + ) + end + end + + context 'when except unknown prop' do + let(:headers) do + { + 'X-Inertia' => true, + 'X-Inertia-Partial-Data' => 'nested_lazy', + 'X-Inertia-Partial-Except' => 'unknown', + 'X-Inertia-Partial-Component' => 'TestComponent', + } + end + + it 'returns props' do + expect(response.parsed_body['props']).to eq( + 'always' => 'always prop', + 'nested_lazy' => { 'first' => 'first nested lazy param' }, + ) + end + end + + context 'when excludes with dot notation' do + let(:headers) do + { + 'X-Inertia' => true, + 'X-Inertia-Partial-Data' => 'nested,nested_lazy', + 'X-Inertia-Partial-Except' => 'nested.first,nested_lazy.first', + 'X-Inertia-Partial-Component' => 'TestComponent', + } + end + + it 'works with dot notation only with simple props' do + expect(response.parsed_body['props']).to eq( + 'always' => 'always prop', + 'nested' => { 'second' => 'second nested param' }, + 'nested_lazy' => { 'first' => 'first nested lazy param' }, + ) + end + end + end + context 'lazy prop rendering' do context 'on first load' do let(:page) { From 6b991316801bce5d335f6a5c8dcf62ccd2de2132 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Sat, 2 Nov 2024 17:09:39 +0300 Subject: [PATCH 5/8] Improve merge_props performance --- lib/inertia_rails/renderer.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/inertia_rails/renderer.rb b/lib/inertia_rails/renderer.rb index b1a0db1..215119c 100644 --- a/lib/inertia_rails/renderer.rb +++ b/lib/inertia_rails/renderer.rb @@ -66,7 +66,11 @@ def shared_data # Functionally, this permits using either string or symbol keys in the controller. Since the results # is cast to json, we should treat string/symbol keys as identical. def merge_props(shared_data, props) - shared_data.deep_symbolize_keys.send(@deep_merge ? :deep_merge : :merge, props.deep_symbolize_keys) + if @deep_merge + shared_data.deep_symbolize_keys.deep_merge!(props.deep_symbolize_keys) + else + shared_data.symbolize_keys.merge(props.symbolize_keys) + end end def computed_props From f35d898149790372475a2be409116cfb97c58fcb Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Sat, 2 Nov 2024 17:20:05 +0300 Subject: [PATCH 6/8] docs: Add InertiaRails.always and drop the warning about the `except` option --- docs/guide/partial-reloads.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/guide/partial-reloads.md b/docs/guide/partial-reloads.md index 1589ddc..04efc44 100644 --- a/docs/guide/partial-reloads.md +++ b/docs/guide/partial-reloads.md @@ -46,9 +46,6 @@ router.visit(url, { ## Except certain props -> [!WARNING] -> The `except` option is not yet supported by the Inertia Rails. - :::tabs key:frameworks == Vue @@ -236,6 +233,11 @@ class UsersController < ApplicationController # OPTIONALLY included on partial reloads # ONLY evaluated when needed users: InertiaRails.lazy { User.all }, + + # ALWAYS included on standard visits + # ALWAYS included on partial reloads + # ALWAYS evaluated + users: InertiaRails.always(User.all), } end end From 13ab57fb5481100fab7491d8433a25f108762990 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Tue, 5 Nov 2024 10:30:13 +0300 Subject: [PATCH 7/8] Support `.visit(path, {except: 'prop')` without `only:` --- lib/inertia_rails/renderer.rb | 4 ++-- lib/patches/request.rb | 2 +- spec/inertia/rendering_spec.rb | 17 +++++++++++++++++ spec/inertia/request_spec.rb | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/inertia_rails/renderer.rb b/lib/inertia_rails/renderer.rb index 215119c..348347f 100644 --- a/lib/inertia_rails/renderer.rb +++ b/lib/inertia_rails/renderer.rb @@ -76,7 +76,7 @@ def merge_props(shared_data, props) def computed_props _props = merge_props(shared_data, props).select do |key, prop| if rendering_partial_component? - key.in?(partial_keys) || prop.is_a?(AlwaysProp) + partial_keys.none? || key.in?(partial_keys) || prop.is_a?(AlwaysProp) else !prop.is_a?(LazyProp) end @@ -130,7 +130,7 @@ def partial_except_keys end def rendering_partial_component? - @request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component + @request.headers['X-Inertia-Partial-Component'] == component end def resolve_component(component) diff --git a/lib/patches/request.rb b/lib/patches/request.rb index ad09c6c..a48c4af 100644 --- a/lib/patches/request.rb +++ b/lib/patches/request.rb @@ -4,6 +4,6 @@ def inertia? end def inertia_partial? - key? 'HTTP_X_INERTIA_PARTIAL_DATA' + key?('HTTP_X_INERTIA_PARTIAL_COMPONENT') end end diff --git a/spec/inertia/rendering_spec.rb b/spec/inertia/rendering_spec.rb index 509acbb..9c49e56 100644 --- a/spec/inertia/rendering_spec.rb +++ b/spec/inertia/rendering_spec.rb @@ -132,6 +132,23 @@ ) end + context 'when except without X-Inertia-Partial-Data' do + let(:headers) {{ + 'X-Inertia' => true, + 'X-Inertia-Partial-Except' => 'nested', + 'X-Inertia-Partial-Component' => 'TestComponent', + }} + + it 'returns all regular and partial props except excepted' do + expect(response.parsed_body['props']).to eq( + 'flat' => 'flat param', + 'lazy' => 'lazy param', + 'always' => 'always prop', + 'nested_lazy' => { 'first' => 'first nested lazy param' }, + ) + end + end + context 'when except always prop' do let(:headers) {{ 'X-Inertia' => true, diff --git a/spec/inertia/request_spec.rb b/spec/inertia/request_spec.rb index ce1dff5..3603679 100644 --- a/spec/inertia/request_spec.rb +++ b/spec/inertia/request_spec.rb @@ -21,7 +21,7 @@ before { get inertia_partial_request_test_path, headers: headers } context 'it is a partial inertia call' do - let(:headers) { { 'X-Inertia' => true, 'X-Inertia-Partial-Data' => 'foo,bar,baz' } } + let(:headers) { { 'X-Inertia' => true, 'X-Inertia-Partial-Component' => 'Component', 'X-Inertia-Partial-Data' => 'foo,bar,baz' } } it { is_expected.to eq 202 } end From 35ac7c8876e1490e284c47e590a8682b852d014b Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Tue, 5 Nov 2024 10:40:47 +0300 Subject: [PATCH 8/8] restrict InertiRails.always to only acept blocks --- docs/guide/partial-reloads.md | 8 +--- lib/inertia_rails/base_prop.rb | 11 +---- lib/inertia_rails/inertia_rails.rb | 4 +- lib/inertia_rails/lazy_prop.rb | 14 +++++++ .../inertia_render_test_controller.rb | 4 +- spec/inertia/lazy_prop_spec.rb | 32 +++++++++++++++ spec/support/shared_examples.rb | 40 +++---------------- 7 files changed, 58 insertions(+), 55 deletions(-) diff --git a/docs/guide/partial-reloads.md b/docs/guide/partial-reloads.md index 04efc44..526e93c 100644 --- a/docs/guide/partial-reloads.md +++ b/docs/guide/partial-reloads.md @@ -201,13 +201,7 @@ On the inverse, you can use the `InertiaRails.always` method to specify that a p class UsersController < ApplicationController def index render inertia: 'Users/Index', props: { - users: InertiaRails.always(User.all), - - # Also works with block: - # users: InertiaRails.always { User.all }, - - # Also works with a lambda: - # users: InertiaRails.always(-> { User.all }), + users: InertiaRails.always { User.all }, } end end diff --git a/lib/inertia_rails/base_prop.rb b/lib/inertia_rails/base_prop.rb index 82e8c3c..1ee723b 100644 --- a/lib/inertia_rails/base_prop.rb +++ b/lib/inertia_rails/base_prop.rb @@ -3,19 +3,12 @@ module InertiaRails # Base class for all props. class BaseProp - def initialize(value = nil, &block) - raise ArgumentError, 'You must provide either a value or a block, not both' if value && block - - @value = value + def initialize(&block) @block = block end def call(controller) - value.respond_to?(:call) ? controller.instance_exec(&value) : value - end - - def value - @value.nil? ? @block : @value + controller.instance_exec(&@block) end end end diff --git a/lib/inertia_rails/inertia_rails.rb b/lib/inertia_rails/inertia_rails.rb index 2c1d8b7..4a38949 100644 --- a/lib/inertia_rails/inertia_rails.rb +++ b/lib/inertia_rails/inertia_rails.rb @@ -19,8 +19,8 @@ def lazy(value = nil, &block) LazyProp.new(value, &block) end - def always(value = nil, &block) - AlwaysProp.new(value, &block) + def always(&block) + AlwaysProp.new(&block) end end end diff --git a/lib/inertia_rails/lazy_prop.rb b/lib/inertia_rails/lazy_prop.rb index 6d24727..b3c01d9 100644 --- a/lib/inertia_rails/lazy_prop.rb +++ b/lib/inertia_rails/lazy_prop.rb @@ -2,5 +2,19 @@ module InertiaRails class LazyProp < BaseProp + def initialize(value = nil, &block) + raise ArgumentError, 'You must provide either a value or a block, not both' if value && block + + @value = value + @block = block + end + + def call(controller) + value.respond_to?(:call) ? controller.instance_exec(&value) : value + end + + def value + @value.nil? ? @block : @value + end end end diff --git a/spec/dummy/app/controllers/inertia_render_test_controller.rb b/spec/dummy/app/controllers/inertia_render_test_controller.rb index c844816..5ab23d4 100644 --- a/spec/dummy/app/controllers/inertia_render_test_controller.rb +++ b/spec/dummy/app/controllers/inertia_render_test_controller.rb @@ -20,7 +20,7 @@ def except_props first: 'first nested param', second: 'second nested param' }, - always: InertiaRails.always('always prop') + always: InertiaRails.always { 'always prop' } } end @@ -54,7 +54,7 @@ def lazy_props def always_props render inertia: 'TestComponent', props: { - always: InertiaRails.always('always prop'), + always: InertiaRails.always { 'always prop' }, regular: 'regular prop', lazy: InertiaRails.lazy do 'lazy prop' diff --git a/spec/inertia/lazy_prop_spec.rb b/spec/inertia/lazy_prop_spec.rb index 7f154eb..755e6f7 100644 --- a/spec/inertia/lazy_prop_spec.rb +++ b/spec/inertia/lazy_prop_spec.rb @@ -1,3 +1,35 @@ RSpec.describe InertiaRails::LazyProp do it_behaves_like 'base prop' + + describe '#call' do + subject(:call) { prop.call(controller) } + let(:prop) { described_class.new('value') } + let(:controller) { ApplicationController.new } + + it { is_expected.to eq('value') } + + context 'with false as value' do + let(:prop) { described_class.new(false) } + + it { is_expected.to eq(false) } + end + + context 'with nil as value' do + let(:prop) { described_class.new(nil) } + + it { is_expected.to eq(nil) } + end + + context 'with a callable value' do + let(:prop) { described_class.new(-> { 'callable' }) } + + it { is_expected.to eq('callable') } + + context 'with dependency on the context of a controller' do + let(:prop) { described_class.new(-> { controller_method }) } + + it { is_expected.to eq('controller_method value') } + end + end + end end diff --git a/spec/support/shared_examples.rb b/spec/support/shared_examples.rb index 75c921e..ac3fe28 100644 --- a/spec/support/shared_examples.rb +++ b/spec/support/shared_examples.rb @@ -1,45 +1,15 @@ RSpec.shared_examples 'base prop' do describe '#call' do subject(:call) { prop.call(controller) } - let(:prop) { described_class.new('value') } + let(:prop) { described_class.new { 'block' } } let(:controller) { ApplicationController.new } - it { is_expected.to eq('value') } + it { is_expected.to eq('block') } - context 'with false as value' do - let(:prop) { described_class.new(false) } + context 'with dependency on the context of a controller' do + let(:prop) { described_class.new { controller_method } } - it { is_expected.to eq(false) } - end - - context 'with nil as value' do - let(:prop) { described_class.new(nil) } - - it { is_expected.to eq(nil) } - end - - context 'with a callable value' do - let(:prop) { described_class.new(-> { 'callable' }) } - - it { is_expected.to eq('callable') } - - context 'with dependency on the context of a controller' do - let(:prop) { described_class.new(-> { controller_method }) } - - it { is_expected.to eq('controller_method value') } - end - end - - context 'with a block' do - let(:prop) { described_class.new { 'block' } } - - it { is_expected.to eq('block') } - - context 'with dependency on the context of a controller' do - let(:prop) { described_class.new { controller_method } } - - it { is_expected.to eq('controller_method value') } - end + it { is_expected.to eq('controller_method value') } end end end