Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,25 @@ def underscore_params
end
```

### `merge_prop_transformer`

**Default**: `->(merge_props:) { merge_props }`

Use `merge_prop_transformer` to apply a transformation to the array of merge prop keys before they're sent to the client. This is particularly useful to maintain consistency when using `prop_transformer` to convert prop keys to `camelCase`, as it ensures that merge props (used with `InertiaRails.merge` and `InertiaRails.deep_merge`) also follow the same naming convention:

```ruby
inertia_config(
prop_transformer: lambda do |props:|
props.deep_transform_keys { |key| key.to_s.camelize(:lower) }
end,
merge_prop_transformer: lambda do |merge_props:|
merge_props.map { |prop| prop.to_s.camelize(:lower) }
end
)
```

Without `merge_prop_transformer`, you would have inconsistent naming where regular props use `camelCase` but merge prop keys remain in `snake_case`. This transformer only affects the array of merge prop keys that gets sent to the client in the `mergeProps` and `deepMergeProps` fields.

### `deep_merge_shared_data`

**Default**: `false`
Expand Down
7 changes: 7 additions & 0 deletions lib/inertia_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class Configuration
# A function that transforms the props before they are sent to the client.
prop_transformer: ->(props:) { props },

# A function that transforms the array of merge props before they are sent to the client.
merge_prop_transformer: ->(merge_props:) { merge_props },

# DEPRECATED: Let Rails decide which layout should be used based on the
# controller configuration.
layout: true,
Expand Down Expand Up @@ -99,6 +102,10 @@ def prop_transformer(props:)
@options[:prop_transformer].call(props: props)
end

def merge_prop_transformer(merge_props:)
@options[:merge_prop_transformer].call(merge_props: merge_props)
end

OPTION_NAMES.each do |option|
unless method_defined?(option)
define_method(option) do
Expand Down
14 changes: 11 additions & 3 deletions lib/inertia_rails/renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,17 @@ def page
prop.match_on.map { |ms| "#{key}.#{ms}" } if prop.match_on.present?
end.flatten

default_page[:mergeProps] = merge_props.map(&:first) if merge_props.present?
default_page[:deepMergeProps] = deep_merge_props.map(&:first) if deep_merge_props.present?
default_page[:matchPropsOn] = match_props_on if match_props_on.present?
if merge_props.present?
default_page[:mergeProps] = configuration.merge_prop_transformer(merge_props: merge_props.map(&:first))
end

if deep_merge_props.present?
default_page[:deepMergeProps] = configuration.merge_prop_transformer(merge_props: deep_merge_props.map(&:first))
end

if match_props_on.present?
default_page[:matchPropsOn] = configuration.merge_prop_transformer(merge_props: match_props_on)
end

default_page
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

class InertiaMergePropTransformerController < ApplicationController
inertia_config(
merge_prop_transformer: lambda do |merge_props:|
merge_props.map { |prop| prop.to_s.camelize(:lower) }
end
)

def with_merge_props
render inertia: 'TestComponent', props: {
snake_case_merge: InertiaRails.merge { 'merge prop' },
another_snake_merge: InertiaRails.merge(match_on: 'id') { [id: 1] },
regular_prop: 'regular prop',
}
end

def with_deep_merge_props
render inertia: 'TestComponent', props: {
snake_case_deep_merge: InertiaRails.deep_merge { { deep: 'merge prop' } },
another_snake_deep_merge: InertiaRails.deep_merge(match_on: 'deep.id') { { deep: [id: 1] } },
regular_prop: 'regular prop',
}
end

def with_both_merge_types
render inertia: 'TestComponent', props: {
snake_case_merge: InertiaRails.merge { 'merge prop' },
snake_case_deep_merge: InertiaRails.deep_merge { { deep: 'merge prop' } },
regular_prop: 'regular prop',
}
end

def no_merge_props
render inertia: 'TestComponent', props: {
regular_prop: 'regular prop',
}
end
end
4 changes: 4 additions & 0 deletions spec/dummy/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
get 'prop_transformer_test' => 'inertia_prop_transformer#just_props'
get 'prop_transformer_with_meta_test' => 'inertia_prop_transformer#props_and_meta'
get 'prop_transformer_no_props_test' => 'inertia_prop_transformer#no_props'
get 'merge_prop_transformer_test' => 'inertia_merge_prop_transformer#with_merge_props'
get 'merge_prop_transformer_deep_test' => 'inertia_merge_prop_transformer#with_deep_merge_props'
get 'merge_prop_transformer_both_test' => 'inertia_merge_prop_transformer#with_both_merge_types'
get 'merge_prop_transformer_no_merge_test' => 'inertia_merge_prop_transformer#no_merge_props'
get 'default_component_test' => 'inertia_rails_mimic#default_component_test'
get 'default_component_with_props_test' => 'inertia_rails_mimic#default_component_with_props_test'
get 'default_component_with_duplicated_props_test' => 'inertia_rails_mimic#default_component_with_duplicated_props_test'
Expand Down
75 changes: 75 additions & 0 deletions spec/inertia/merge_prop_transformer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true

require_relative '../../lib/inertia_rails/rspec'
RSpec.describe 'merge props can be transformed', type: :request, inertia: true do
let(:headers) do
{
'X-Inertia' => true,
'X-Inertia-Partial-Component' => 'TestComponent',
}
end

context 'merge props are provided' do
it 'transforms the merge props from snake_case to camelCase' do
get merge_prop_transformer_test_path, headers: headers

expect_inertia.to render_component('TestComponent')
.and have_exact_props({
'snake_case_merge' => 'merge prop',
'another_snake_merge' => [{ 'id' => 1 }],
'regular_prop' => 'regular prop',
})

# Check that mergeProps array contains transformed keys
expect(response.parsed_body['mergeProps']).to eq(['snakeCaseMerge', 'anotherSnakeMerge'])
end
end

context 'deep merge props are provided' do
it 'transforms the deep merge props from snake_case to camelCase' do
get merge_prop_transformer_deep_test_path, headers: headers

expect_inertia.to render_component('TestComponent')
.and have_exact_props({
'snake_case_deep_merge' => { 'deep' => 'merge prop' },
'another_snake_deep_merge' => { 'deep' => [{ 'id' => 1 }] },
'regular_prop' => 'regular prop',
})

# Check that deepMergeProps array contains transformed keys
expect(response.parsed_body['deepMergeProps']).to eq(['snakeCaseDeepMerge', 'anotherSnakeDeepMerge'])
end
end

context 'both merge and deep merge props are provided' do
it 'transforms both types of merge props from snake_case to camelCase' do
get merge_prop_transformer_both_test_path, headers: headers

expect_inertia.to render_component('TestComponent')
.and have_exact_props({
'snake_case_merge' => 'merge prop',
'snake_case_deep_merge' => { 'deep' => 'merge prop' },
'regular_prop' => 'regular prop',
})

# Check that both mergeProps and deepMergeProps arrays contain transformed keys
expect(response.parsed_body['mergeProps']).to eq(['snakeCaseMerge'])
expect(response.parsed_body['deepMergeProps']).to eq(['snakeCaseDeepMerge'])
end
end

context 'no merge props are provided' do
it 'does not error and does not include mergeProps or deepMergeProps' do
get merge_prop_transformer_no_merge_test_path, headers: headers

expect_inertia.to render_component('TestComponent')
.and have_exact_props({
'regular_prop' => 'regular prop',
})

# Check that no merge props arrays are present
expect(response.parsed_body).not_to have_key('mergeProps')
expect(response.parsed_body).not_to have_key('deepMergeProps')
end
end
end