inertia_rails 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5626c22ecacdfaa9d46b04fe63027a941af3ee6f9e32716943072a547f12bb8f
4
- data.tar.gz: 3ad0c5ef9d0f2943a70d76218b1d97dce7cef8079ee0ef0bcc7e337ffeef607c
3
+ metadata.gz: 27e7436cecef40102f1e1ca1971c75b182195e3291f55f94981ef8c87359d9d4
4
+ data.tar.gz: 50c9634e36e040732e9bf42e7770a3d759e4930513b4fb54d2761e905689bc24
5
5
  SHA512:
6
- metadata.gz: 1e67ddf363fef24d94688cc0f9f51f46c62aec3265acab8a3e656923cc227b05e812c56d95e2fb5996c2acca909d99ed2af1863f17420ea6ec387695af14cf8c
7
- data.tar.gz: b412652b57ae50161487667e34f1d35cf396bcfde11f2ac3fe8f574d0670374722c5ff1b31e3a83b5c11dc40687afd9945f45734f0e9549f512480bbf22fb801
6
+ metadata.gz: 2653faf355cc672ebe5faec59fffdfe928cddd8b045ba114d5e8fafe01e3c5eb74ed47ac63336e62e1080c5e616a1ce3ac68fa8475644a1caf9f70e0206ce327
7
+ data.tar.gz: f7ae1c4be29f75140a42a08cd31c8ca946b1b5bb39a681c8bd2b0c8db71c716bcf3368bc0f37b573ffe84906686d57b191ead1e1143de3d19bf4441bab06c09f
data/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.1.0] - 2023-08-21
8
+
9
+ ### Features
10
+
11
+ * CSRF protection works without additional configuration now.
12
+ * Optional deep merging of shared props.
13
+
14
+ ### Fixes
15
+
16
+ * Document Inertia headers. @buhrmi
17
+ * Documentation typo fix. @lujanfernaud
18
+ * Changelog URI fix. @PedroAugustoRamalhoDuarte
19
+
7
20
  ## [3.0.0] - 2022-09-22
8
21
 
9
22
  * Allow rails layout to set inertia layout. Thanks @ElMassimo!
data/README.md CHANGED
@@ -79,7 +79,7 @@ end
79
79
 
80
80
  ### Shared Data
81
81
 
82
- If you have data that you want to be provided as a prop to every component (a common use-case is informationa about the authenticated user) you can use the `shared_data` controller method.
82
+ If you have data that you want to be provided as a prop to every component (a common use-case is information about the authenticated user) you can use the `shared_data` controller method.
83
83
 
84
84
  ```ruby
85
85
  class EventsController < ApplicationController
@@ -101,6 +101,76 @@ class EventsController < ApplicationController
101
101
  end
102
102
  ```
103
103
 
104
+ #### Deep Merging Shared Data
105
+
106
+ By default, Inertia will shallow merge data defined in an action with the shared data. You might want a deep merge. Imagine using shared data to represent defaults you'll override sometimes.
107
+
108
+ ```ruby
109
+ class ApplicationController
110
+ inertia_share do
111
+ { basketball_data: { points: 50, rebounds: 100 } }
112
+ end
113
+ end
114
+ ```
115
+
116
+ Let's say we want a particular action to change only part of that data structure. The renderer accepts a `deep_merge` option:
117
+
118
+ ```ruby
119
+ class CrazyScorersController < ApplicationController
120
+ def index
121
+ render inertia: 'CrazyScorersComponent',
122
+ props: { basketball_data: { points: 100 } },
123
+ deep_merge: true
124
+ end
125
+ end
126
+
127
+ # The renderer will send this to the frontend:
128
+ {
129
+ basketball_data: {
130
+ points: 100,
131
+ rebounds: 100,
132
+ }
133
+ }
134
+ ```
135
+
136
+ Deep merging can be set as the project wide default via the InertiaRails configuration:
137
+
138
+ ```ruby
139
+ # config/initializers/some_initializer.rb
140
+ InertiaRails.configure do |config|
141
+ config.deep_merge_shared_data = true
142
+ end
143
+
144
+ ```
145
+
146
+ If deep merging is enabled by default, it's possible to opt out within the action:
147
+
148
+ ```ruby
149
+ class CrazyScorersController < ApplicationController
150
+ inertia_share do
151
+ {
152
+ basketball_data: {
153
+ points: 50,
154
+ rebounds: 10,
155
+ }
156
+ }
157
+ end
158
+
159
+ def index
160
+ render inertia: 'CrazyScorersComponent',
161
+ props: { basketball_data: { points: 100 } },
162
+ deep_merge: false
163
+ end
164
+ end
165
+
166
+ # Even if deep merging is set by default, since the renderer has `deep_merge: false`, it will send a shallow merge to the frontend:
167
+ {
168
+ basketball_data: {
169
+ points: 100,
170
+ }
171
+ }
172
+ ```
173
+
104
174
  ### Lazy Props
105
175
 
106
176
  On the front end, Inertia supports the concept of "partial reloads" where only the props requested are returned by the server. Sometimes, you may want to use this flow to avoid processing a particularly slow prop on the intial load. In this case, you can use Lazy props. Lazy props aren't evaluated unless they're specifically requested by name in a partial reload.
@@ -119,7 +189,9 @@ inertia 'about' => 'AboutComponent'
119
189
 
120
190
  ### SSR
121
191
 
122
- Enable SSR via the config settings for `ssr_enabled` and `ssr_url`
192
+ Enable SSR via the config settings for `ssr_enabled` and `ssr_url`.
193
+
194
+ When using SSR, don't forget to add `<%= inertia_headers %>` to the `<head>` of your `application.html.erb`.
123
195
 
124
196
  ## Configuration
125
197
 
@@ -137,6 +209,8 @@ InertiaRails.configure do |config|
137
209
  # ssr specific options
138
210
  config.ssr_enabled = false
139
211
  config.ssr_url = 'http://localhost:13714'
212
+
213
+ config.deep_merge_shared_data = false
140
214
 
141
215
  end
142
216
  ```
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
16
  spec.metadata["source_code_uri"] = spec.homepage
17
- spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
17
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
18
18
 
19
19
  # Specify which files should be added to the gem when it is released.
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -1,16 +1,12 @@
1
1
  import { App } from '@inertiajs/inertia-react';
2
2
  import React from 'react';
3
3
  import { render } from 'react-dom';
4
- import axios from 'axios';
5
4
  import { InertiaProgress } from '@inertiajs/progress';
6
5
 
7
6
  document.addEventListener('DOMContentLoaded', () => {
8
7
  InertiaProgress.init();
9
8
  const el = document.getElementById('app')
10
9
 
11
- const csrfToken = document.querySelector('meta[name=csrf-token]').content;
12
- axios.defaults.headers.common['X-CSRF-Token'] = csrfToken;
13
-
14
10
  render(
15
11
  <App
16
12
  initialPage={JSON.parse(el.dataset.page)}
@@ -18,4 +14,4 @@ document.addEventListener('DOMContentLoaded', () => {
18
14
  />,
19
15
  el
20
16
  )
21
- });
17
+ });
@@ -1,12 +1,7 @@
1
- import axios from 'axios'
2
-
3
1
  import { createInertiaApp } from '@inertiajs/inertia-svelte'
4
2
  import { InertiaProgress } from '@inertiajs/progress'
5
3
 
6
4
  document.addEventListener('DOMContentLoaded', () => {
7
- const csrfToken = document.querySelector('meta[name=csrf-token]').content
8
- axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
9
-
10
5
  InertiaProgress.init()
11
6
 
12
7
  createInertiaApp({
@@ -16,4 +11,4 @@ document.addEventListener('DOMContentLoaded', () => {
16
11
  new App({ target: el, props })
17
12
  },
18
13
  })
19
- })
14
+ })
@@ -1,13 +1,9 @@
1
- import axios from 'axios'
2
1
  import Vue from 'vue'
3
2
 
4
3
  import { app, plugin } from '@inertiajs/inertia-vue'
5
4
  import { InertiaProgress } from '@inertiajs/progress'
6
5
 
7
6
  document.addEventListener('DOMContentLoaded', () => {
8
- const csrfToken = document.querySelector('meta[name=csrf-token]').content
9
- axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
10
-
11
7
  InertiaProgress.init();
12
8
  const el = document.getElementById('app')
13
9
 
@@ -11,6 +11,10 @@ module InertiaRails
11
11
  InertiaRails.share(errors: session[:inertia_errors]) if session[:inertia_errors].present?
12
12
  end
13
13
  helper ::InertiaRails::Helper
14
+
15
+ after_action do
16
+ cookies['XSRF-TOKEN'] = form_authenticity_token unless request.inertia? || !protect_against_forgery?
17
+ end
14
18
  end
15
19
 
16
20
  module ClassMethods
@@ -13,7 +13,9 @@ module InertiaRails
13
13
 
14
14
  # "Getters"
15
15
  def self.shared_data(controller)
16
- shared_plain_data.merge!(evaluated_blocks(controller, shared_blocks))
16
+ shared_plain_data.
17
+ merge!(evaluated_blocks(controller, shared_blocks)).
18
+ with_indifferent_access
17
19
  end
18
20
 
19
21
  def self.version
@@ -40,6 +42,10 @@ module InertiaRails
40
42
  self.threadsafe_html_headers || []
41
43
  end
42
44
 
45
+ def self.deep_merge_shared_data?
46
+ Configuration.deep_merge_shared_data
47
+ end
48
+
43
49
  # "Setters"
44
50
  def self.share(**args)
45
51
  self.shared_plain_data = self.shared_plain_data.merge(args)
@@ -71,6 +77,7 @@ module InertiaRails
71
77
  mattr_accessor(:ssr_enabled) { false }
72
78
  mattr_accessor(:ssr_url) { 'http://localhost:13714' }
73
79
  mattr_accessor(:default_render) { false }
80
+ mattr_accessor(:deep_merge_shared_data) { false }
74
81
 
75
82
  def self.evaluated_version
76
83
  self.version.respond_to?(:call) ? self.version.call : self.version
@@ -18,6 +18,7 @@ module InertiaRails
18
18
  end
19
19
 
20
20
  def response
21
+ copy_xsrf_to_csrf!
21
22
  status, headers, body = @app.call(@env)
22
23
  request = ActionDispatch::Request.new(@env)
23
24
 
@@ -89,6 +90,10 @@ module InertiaRails
89
90
  request.flash.keep
90
91
  Rack::Response.new('', 409, {'X-Inertia-Location' => request.original_url}).finish
91
92
  end
93
+
94
+ def copy_xsrf_to_csrf!
95
+ @env['HTTP_X_CSRF_TOKEN'] = @env['HTTP_X_XSRF_TOKEN'] if @env['HTTP_X_XSRF_TOKEN'] && inertia_request?
96
+ end
92
97
  end
93
98
  end
94
99
  end
@@ -6,14 +6,15 @@ module InertiaRails
6
6
  class Renderer
7
7
  attr_reader :component, :view_data
8
8
 
9
- def initialize(component, controller, request, response, render_method, props:, view_data:)
9
+ def initialize(component, controller, request, response, render_method, props: nil, view_data: nil, deep_merge: nil)
10
10
  @component = component.is_a?(TrueClass) ? "#{controller.controller_path}/#{controller.action_name}" : component
11
11
  @controller = controller
12
12
  @request = request
13
13
  @response = response
14
14
  @render_method = render_method
15
- @props = props || controller.inertia_view_assigns
15
+ @props = props ? props.with_indifferent_access : controller.inertia_view_assigns.with_indifferent_access
16
16
  @view_data = view_data || {}
17
+ @deep_merge = !deep_merge.nil? ? deep_merge : InertiaRails.deep_merge_shared_data?
17
18
  end
18
19
 
19
20
  def render
@@ -41,8 +42,8 @@ module InertiaRails
41
42
  @controller.send(:inertia_layout)
42
43
  end
43
44
 
44
- def props
45
- _props = ::InertiaRails.shared_data(@controller).merge(@props).select do |key, prop|
45
+ def computed_props
46
+ _props = ::InertiaRails.shared_data(@controller).send(prop_merge_method, @props).select do |key, prop|
46
47
  if rendering_partial_component?
47
48
  key.in? partial_keys
48
49
  else
@@ -50,13 +51,13 @@ module InertiaRails
50
51
  end
51
52
  end
52
53
 
53
- deep_transform_values(_props, lambda {|prop| prop.respond_to?(:call) ? @controller.instance_exec(&prop) : prop })
54
+ deep_transform_values(_props, lambda {|prop| prop.respond_to?(:call) ? @controller.instance_exec(&prop) : prop }).with_indifferent_access
54
55
  end
55
56
 
56
57
  def page
57
58
  {
58
59
  component: component,
59
- props: props,
60
+ props: computed_props,
60
61
  url: @request.original_fullpath,
61
62
  version: ::InertiaRails.version,
62
63
  }
@@ -75,5 +76,9 @@ module InertiaRails
75
76
  def rendering_partial_component?
76
77
  @request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component
77
78
  end
79
+
80
+ def prop_merge_method
81
+ @deep_merge ? :deep_merge : :merge
82
+ end
78
83
  end
79
84
  end
@@ -74,7 +74,7 @@ end
74
74
 
75
75
  RSpec::Matchers.define :have_exact_props do |expected_props|
76
76
  match do |inertia|
77
- expect(inertia.props).to eq expected_props
77
+ expect(inertia.props).to eq expected_props.with_indifferent_access
78
78
  end
79
79
 
80
80
  failure_message do |inertia|
@@ -84,7 +84,7 @@ end
84
84
 
85
85
  RSpec::Matchers.define :include_props do |expected_props|
86
86
  match do |inertia|
87
- expect(inertia.props).to include expected_props
87
+ expect(inertia.props).to include expected_props.with_indifferent_access
88
88
  end
89
89
 
90
90
  failure_message do |inertia|
@@ -1,3 +1,3 @@
1
1
  module InertiaRails
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0"
3
3
  end
data/lib/inertia_rails.rb CHANGED
@@ -15,6 +15,7 @@ ActionController::Renderers.add :inertia do |component, options|
15
15
  method(:render),
16
16
  props: options[:props],
17
17
  view_data: options[:view_data],
18
+ deep_merge: options[:deep_merge],
18
19
  ).render
19
20
  end
20
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inertia_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Knoles
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-09-22 00:00:00.000000000 Z
13
+ date: 2023-08-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -198,7 +198,7 @@ licenses:
198
198
  metadata:
199
199
  homepage_uri: https://github.com/inertiajs/inertia-rails
200
200
  source_code_uri: https://github.com/inertiajs/inertia-rails
201
- changelog_uri: https://github.com/inertiajs/inertia-rails/CHANGELOG.md
201
+ changelog_uri: https://github.com/inertiajs/inertia-rails/blob/master/CHANGELOG.md
202
202
  post_install_message:
203
203
  rdoc_options: []
204
204
  require_paths:
@@ -214,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
214
  - !ruby/object:Gem::Version
215
215
  version: '0'
216
216
  requirements: []
217
- rubygems_version: 3.3.3
217
+ rubygems_version: 3.4.10
218
218
  signing_key:
219
219
  specification_version: 4
220
220
  summary: Inertia adapter for Rails