inertia_rails 1.4.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef2ef33ca24036a92d67ec557bab99829468a7f9546422b68a703624bd52489d
4
- data.tar.gz: 6beb16df6b7511813b62e42e91fbb7d0a251264b2e802e0e0345b04bd08700ac
3
+ metadata.gz: f3300d5a0d8ba1a4a433151b232dc06a2fbbdc337f8c1948b6a1fd52dbc20b4d
4
+ data.tar.gz: 3a62632643c8761c00fe3b462f2710d094a9adb06df0d7942b516c669eec7515
5
5
  SHA512:
6
- metadata.gz: 5e2d7527c48047f950207b163fa539b6b4735655d501a573035a782cb623f5973a74789574be6722bbf7bd4088835c5a486d9a8962df02d17473c4c2d42a0012
7
- data.tar.gz: 96d8302e0fd851874d14ef2cee34c013278924c9e619d7302a2a66ae2a3c5dbd7c3a5e3a7ee2e01f8849adfbd0f54e65b1661cfeeb27320e8f94b415d8ca5567
6
+ metadata.gz: 29d82e990a312f2392f14b209c10d6cb198d1f335d0b0e33b2d6821d8bcbc51adeb6d489362fbf2f124bc0b3605d152eb8470221c061eaf6dcae5083f5e86a79
7
+ data.tar.gz: 44565a5b1b36086a7baf965671fd09d5b1e75f3ed393c7de459e5a3c4a7a2d17bd5f485f0f9b68261631cd47cd371439357cd1a852ed2d6a82aa71268c51aaf8
@@ -8,9 +8,10 @@ jobs:
8
8
  fail-fast: false
9
9
  matrix:
10
10
  ruby: [2.6, 2.7]
11
+ rails: ['5.0', '5.1', '5.2', '6.0']
11
12
 
12
13
  runs-on: ubuntu-latest
13
- name: Test against Ruby ${{ matrix.ruby }}
14
+ name: Test against Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }}
14
15
 
15
16
  steps:
16
17
  - uses: actions/checkout@v2
@@ -24,7 +25,10 @@ jobs:
24
25
  ruby-version: ${{ matrix.ruby }}
25
26
 
26
27
  - name: Install gems
28
+ env:
29
+ MATRIX_RAILS_VERSION: ${{ matrix.rails }}
27
30
  run: |
31
+ export BUNDLE_GEMFILE="${GITHUB_WORKSPACE}/gemfiles/rails_${MATRIX_RAILS_VERSION}.gemfile"
28
32
  gem install bundler
29
33
  bundle install --jobs 4 --retry 3
30
34
 
data/.gitignore CHANGED
@@ -17,3 +17,6 @@
17
17
 
18
18
  # rspec failure tracking
19
19
  .rspec_status
20
+
21
+ # Appraisal
22
+ gemfiles/*.gemfile.lock
@@ -0,0 +1,15 @@
1
+ appraise "rails-6.0" do
2
+ gem "rails", "~> 6.0.3", '>= 6.0.3.2'
3
+ end
4
+
5
+ appraise "rails-5.2" do
6
+ gem "rails", "~> 5.2.4", '>= 5.2.4.3'
7
+ end
8
+
9
+ appraise "rails-5.1" do
10
+ gem "rails", "~> 5.1.7"
11
+ end
12
+
13
+ appraise "rails-5.0" do
14
+ gem "rails", "~> 5.0.7", '>= 5.0.7.2'
15
+ end
@@ -4,6 +4,29 @@ 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
+ ## [1.7.1] - 2020-11-24
8
+
9
+ * Fix the definition for InertiaRails::Lazy to avoid an uninitialized constant error when booting an application.
10
+
11
+ ## [1.7.0] - 2020-11-24
12
+
13
+ * Add support for "lazy" props while rendering. These are props that never compute on the initial page load. The only render during a partial update that calls for them explicitly.
14
+
15
+ ## [1.6.0] - 2020-11-20
16
+
17
+ * Built in error sharing across redirects! adding `{ inertia: { errors: 'errors go here' } }` as an option in `redirect_to` will automatically feed an `errors` prop to whatever is rendered after the redirect.
18
+ * Set content type to json for Inertia responses
19
+ * Return the original response status with Inertia responses
20
+
21
+ ## [1.5.0] - 2020-10-07
22
+
23
+ * Test against multiple Rails versions in Github Actions
24
+ * Add the `inertia_location` controller method that forces a full page refresh
25
+
26
+ ## [1.4.1] - 2020-08-06
27
+
28
+ * Fixed a bug involving threadsafe versions and layouts
29
+
7
30
  ## [1.4.0] - 2020-07-09
8
31
 
9
32
  * Fixed Ruby 2.7 deprecation warnings
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.0.7", ">= 5.0.7.2"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.1.7"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.2.4", ">= 5.2.4.3"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 6.0.3", ">= 6.0.3.2"
6
+
7
+ gemspec path: "../"
@@ -25,10 +25,12 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
+ spec.add_runtime_dependency "rails", '>= 5'
29
+
28
30
  spec.add_development_dependency "bundler", "~> 2.0"
29
31
  spec.add_development_dependency "rake", "~> 13.0"
30
32
  spec.add_development_dependency "rspec-rails", "~> 4.0"
31
- spec.add_development_dependency "rails"
32
33
  spec.add_development_dependency "rails-controller-testing"
33
34
  spec.add_development_dependency "sqlite3"
35
+ spec.add_development_dependency "appraisal"
34
36
  end
@@ -4,6 +4,13 @@ module InertiaRails
4
4
  module Controller
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ included do
8
+ before_action do
9
+ # :inertia_errors are deleted from the session by the middleware
10
+ InertiaRails.share(errors: session[:inertia_errors]) if session[:inertia_errors].present?
11
+ end
12
+ end
13
+
7
14
  module ClassMethods
8
15
  def inertia_share(**args, &block)
9
16
  before_action do
@@ -12,5 +19,18 @@ module InertiaRails
12
19
  end
13
20
  end
14
21
  end
22
+
23
+ def inertia_location(url)
24
+ headers['X-Inertia-Location'] = url
25
+ head :conflict
26
+ end
27
+
28
+ def redirect_to(options = {}, response_options = {})
29
+ if (inertia_errors = response_options.fetch(:inertia, {}).fetch(:errors, nil))
30
+ session[:inertia_errors] = inertia_errors
31
+ end
32
+
33
+ super(options, response_options)
34
+ end
15
35
  end
16
36
  end
@@ -1,3 +1,7 @@
1
+ # Needed for `thread_mattr_accessor`
2
+ require 'active_support/core_ext/module/attribute_accessors_per_thread'
3
+ require 'inertia_rails/lazy'
4
+
1
5
  module InertiaRails
2
6
  thread_mattr_accessor :threadsafe_shared_plain_data
3
7
  thread_mattr_accessor :threadsafe_shared_blocks
@@ -33,31 +37,19 @@ module InertiaRails
33
37
  self.shared_blocks = []
34
38
  end
35
39
 
40
+ def self.lazy(value = nil, &block)
41
+ InertiaRails::Lazy.new(value, &block)
42
+ end
43
+
36
44
  private
37
45
 
38
46
  module Configuration
39
- thread_mattr_accessor :threadsafe_layout
40
- thread_mattr_accessor :threadsafe_version
47
+ mattr_accessor(:layout) { 'application' }
48
+ mattr_accessor(:version) { nil }
41
49
 
42
50
  def self.evaluated_version
43
51
  self.version.respond_to?(:call) ? self.version.call : self.version
44
52
  end
45
-
46
- def self.layout
47
- self.threadsafe_layout || 'application'
48
- end
49
-
50
- def self.layout=(val)
51
- self.threadsafe_layout = val
52
- end
53
-
54
- def self.version
55
- self.threadsafe_version
56
- end
57
-
58
- def self.version=(val)
59
- self.threadsafe_version = val
60
- end
61
53
  end
62
54
 
63
55
  # Getters and setters to provide default values for the threadsafe attributes
@@ -0,0 +1,28 @@
1
+ module InertiaRails
2
+ class Lazy
3
+ def initialize(value = nil, &block)
4
+ @value = value
5
+ @block = block
6
+ end
7
+
8
+ def call
9
+ to_proc.call
10
+ end
11
+
12
+ def to_proc
13
+ # This is called by controller.instance_exec, which changes self to the
14
+ # controller instance. That makes the instance variables unavailable to the
15
+ # proc via closure. Copying the instance variables to local variables before
16
+ # the proc is returned keeps them in scope for the returned proc.
17
+ value = @value
18
+ block = @block
19
+ if value.respond_to?(:call)
20
+ value
21
+ elsif value
22
+ Proc.new { value }
23
+ else
24
+ block
25
+ end
26
+ end
27
+ end
28
+ end
@@ -3,41 +3,78 @@ module InertiaRails
3
3
  def initialize(app)
4
4
  @app = app
5
5
  end
6
-
6
+
7
7
  def call(env)
8
+ @env = env
9
+
8
10
  status, headers, body = @app.call(env)
9
11
  request = ActionDispatch::Request.new(env)
10
12
 
11
13
  ::InertiaRails.reset!
12
-
13
- return [status, headers, body] unless env['HTTP_X_INERTIA'].present?
14
-
15
- return force_refresh(request) if stale?(env['REQUEST_METHOD'], env['HTTP_X_INERTIA_VERSION'])
16
-
17
- if is_redirect_status?(status) &&
18
- is_non_get_redirectable_method?(env['REQUEST_METHOD'])
19
- status = 303
20
- end
21
-
22
- [status, headers, body]
23
- end
24
-
14
+
15
+ # Inertia errors are added to the session via redirect_to
16
+ request.session.delete(:inertia_errors) unless keep_inertia_errors?(status)
17
+
18
+ status = 303 if inertia_non_post_redirect?(status)
19
+
20
+ return stale_inertia_get? ? force_refresh(request) : [status, headers, body]
21
+ end
22
+
25
23
  private
26
-
27
- def is_redirect_status?(status)
24
+
25
+ def keep_inertia_errors?(status)
26
+ redirect_status?(status) || stale_inertia_request?
27
+ end
28
+
29
+ def stale_inertia_request?
30
+ inertia_request? && version_stale?
31
+ end
32
+
33
+ def redirect_status?(status)
28
34
  [301, 302].include? status
29
35
  end
30
-
31
- def is_non_get_redirectable_method?(request_method)
36
+
37
+ def non_get_redirectable_method?
32
38
  ['PUT', 'PATCH', 'DELETE'].include? request_method
33
39
  end
34
-
35
- def stale?(request_method, inertia_version)
36
- sent_version = InertiaRails.version.is_a?(Numeric) ? inertia_version.to_f : inertia_version
37
- saved_version = InertiaRails.version.is_a?(Numeric) ? InertiaRails.version.to_f : InertiaRails.version
38
- request_method == 'GET' && sent_version != saved_version
40
+
41
+ def inertia_non_post_redirect?(status)
42
+ inertia_request? && redirect_status?(status) && non_get_redirectable_method?
43
+ end
44
+
45
+ def stale_inertia_get?
46
+ get? && stale_inertia_request?
39
47
  end
40
-
48
+
49
+ def get?
50
+ request_method == 'GET'
51
+ end
52
+
53
+ def request_method
54
+ @env['REQUEST_METHOD']
55
+ end
56
+
57
+ def inertia_version
58
+ @env['HTTP_X_INERTIA_VERSION']
59
+ end
60
+
61
+ def inertia_request?
62
+ @env['HTTP_X_INERTIA'].present?
63
+ end
64
+
65
+ def version_stale?
66
+ sent_version != saved_version
67
+ end
68
+
69
+ def sent_version
70
+ return nil if inertia_version.nil?
71
+ InertiaRails.version.is_a?(Numeric) ? inertia_version.to_f : inertia_version
72
+ end
73
+
74
+ def saved_version
75
+ InertiaRails.version.is_a?(Numeric) ? InertiaRails.version.to_f : InertiaRails.version
76
+ end
77
+
41
78
  def force_refresh(request)
42
79
  request.flash.keep
43
80
  Rack::Response.new('', 409, {'X-Inertia-Location' => request.original_url}).finish
@@ -18,7 +18,7 @@ module InertiaRails
18
18
  if @request.headers['X-Inertia']
19
19
  @response.set_header('Vary', 'Accept')
20
20
  @response.set_header('X-Inertia', 'true')
21
- @render_method.call json: page, status: 200
21
+ @render_method.call json: page, status: @response.status, content_type: Mime[:json]
22
22
  else
23
23
  @render_method.call template: 'inertia', layout: ::InertiaRails.layout, locals: (view_data).merge({page: page})
24
24
  end
@@ -27,13 +27,13 @@ module InertiaRails
27
27
  private
28
28
 
29
29
  def props
30
- only = (@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact.map(&:to_sym)
31
-
32
- _props = ::InertiaRails.shared_data(@controller).merge(@props)
33
-
34
- _props = (only.any? && @request.headers['X-Inertia-Partial-Component'] == component) ?
35
- _props.select {|key| key.in? only} :
36
- _props
30
+ _props = ::InertiaRails.shared_data(@controller).merge(@props).select do |key, prop|
31
+ if rendering_partial_component?
32
+ key.in? partial_keys
33
+ else
34
+ !prop.is_a?(InertiaRails::Lazy)
35
+ end
36
+ end
37
37
 
38
38
  deep_transform_values(_props, lambda {|prop| prop.respond_to?(:call) ? @controller.instance_exec(&prop) : prop })
39
39
  end
@@ -52,5 +52,13 @@ module InertiaRails
52
52
 
53
53
  hash.transform_values {|value| deep_transform_values(value, proc)}
54
54
  end
55
+
56
+ def partial_keys
57
+ (@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact.map(&:to_sym)
58
+ end
59
+
60
+ def rendering_partial_component?
61
+ @request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component
62
+ end
55
63
  end
56
64
  end
@@ -1,3 +1,3 @@
1
1
  module InertiaRails
2
- VERSION = "1.4.0"
2
+ VERSION = "1.7.1"
3
3
  end
@@ -11,13 +11,7 @@ if defined?(ActionDispatch::DebugExceptions)
11
11
  require 'patches/debug_exceptions/patch-5-1'
12
12
  elsif ActionPack.version.to_s >= '5.0'
13
13
  require 'patches/debug_exceptions/patch-5-0'
14
- elsif ActionPack.version.to_s >= '4.2'
15
- require 'patches/debug_exceptions/patch-4-2'
16
- elsif ActionPack.version.to_s >= '4.1'
17
- require 'patches/debug_exceptions/patch-4-1'
18
14
  else
19
- # No patch required, because text rendering for
20
- # XHR requests was introduced with Rails 4.1:
21
- # https://github.com/rails/rails/pull/11960
15
+ # This gem supports Rails 5 or later
22
16
  end
23
17
  end
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: 1.4.0
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Knoles
@@ -10,8 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2020-07-09 00:00:00.000000000 Z
13
+ date: 2020-11-24 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '5'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '5'
15
29
  - !ruby/object:Gem::Dependency
16
30
  name: bundler
17
31
  requirement: !ruby/object:Gem::Requirement
@@ -55,7 +69,7 @@ dependencies:
55
69
  - !ruby/object:Gem::Version
56
70
  version: '4.0'
57
71
  - !ruby/object:Gem::Dependency
58
- name: rails
72
+ name: rails-controller-testing
59
73
  requirement: !ruby/object:Gem::Requirement
60
74
  requirements:
61
75
  - - ">="
@@ -69,7 +83,7 @@ dependencies:
69
83
  - !ruby/object:Gem::Version
70
84
  version: '0'
71
85
  - !ruby/object:Gem::Dependency
72
- name: rails-controller-testing
86
+ name: sqlite3
73
87
  requirement: !ruby/object:Gem::Requirement
74
88
  requirements:
75
89
  - - ">="
@@ -83,7 +97,7 @@ dependencies:
83
97
  - !ruby/object:Gem::Version
84
98
  version: '0'
85
99
  - !ruby/object:Gem::Dependency
86
- name: sqlite3
100
+ name: appraisal
87
101
  requirement: !ruby/object:Gem::Requirement
88
102
  requirements:
89
103
  - - ">="
@@ -108,6 +122,7 @@ files:
108
122
  - ".github/workflows/push.yml"
109
123
  - ".gitignore"
110
124
  - ".rspec"
125
+ - Appraisals
111
126
  - CHANGELOG.md
112
127
  - CODE_OF_CONDUCT.md
113
128
  - Gemfile
@@ -117,19 +132,22 @@ files:
117
132
  - app/views/inertia.html.erb
118
133
  - bin/console
119
134
  - bin/setup
135
+ - gemfiles/rails_5.0.gemfile
136
+ - gemfiles/rails_5.1.gemfile
137
+ - gemfiles/rails_5.2.gemfile
138
+ - gemfiles/rails_6.0.gemfile
120
139
  - inertia_rails.gemspec
121
140
  - lib/inertia_rails.rb
122
141
  - lib/inertia_rails/controller.rb
123
142
  - lib/inertia_rails/engine.rb
124
143
  - lib/inertia_rails/inertia_rails.rb
144
+ - lib/inertia_rails/lazy.rb
125
145
  - lib/inertia_rails/middleware.rb
126
146
  - lib/inertia_rails/renderer.rb
127
147
  - lib/inertia_rails/rspec.rb
128
148
  - lib/inertia_rails/version.rb
129
149
  - lib/patches/better_errors.rb
130
150
  - lib/patches/debug_exceptions.rb
131
- - lib/patches/debug_exceptions/patch-4-1.rb
132
- - lib/patches/debug_exceptions/patch-4-2.rb
133
151
  - lib/patches/debug_exceptions/patch-5-0.rb
134
152
  - lib/patches/debug_exceptions/patch-5-1.rb
135
153
  - lib/patches/request.rb
@@ -155,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
173
  - !ruby/object:Gem::Version
156
174
  version: '0'
157
175
  requirements: []
158
- rubygems_version: 3.0.3
176
+ rubygems_version: 3.1.4
159
177
  signing_key:
160
178
  specification_version: 4
161
179
  summary: Inertia adapter for Rails
@@ -1,41 +0,0 @@
1
- # Patch ActionDispatch::DebugExceptions to render HTML for Inertia requests
2
- #
3
- # Original source:
4
- # https://github.com/rails/rails/blob/4-1-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
5
- #
6
-
7
- ActionDispatch::DebugExceptions.class_eval do
8
- prepend(InertiaDebugExceptions = Module.new do
9
- def render_exception(env, exception)
10
- wrapper = ExceptionWrapper.new(env, exception)
11
- log_error(env, wrapper)
12
-
13
- if env['action_dispatch.show_detailed_exceptions']
14
- request = Request.new(env)
15
- template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
16
- request: request,
17
- exception: wrapper.exception,
18
- application_trace: wrapper.application_trace,
19
- framework_trace: wrapper.framework_trace,
20
- full_trace: wrapper.full_trace,
21
- routes_inspector: routes_inspector(exception),
22
- source_extract: wrapper.source_extract,
23
- line_number: wrapper.line_number,
24
- file: wrapper.file
25
- )
26
- file = "rescues/#{wrapper.rescue_template}"
27
-
28
- if request.xhr? && !request.headers['X-Inertia'] # <<<< this line is changed only
29
- body = template.render(template: file, layout: false, formats: [:text])
30
- format = "text/plain"
31
- else
32
- body = template.render(template: file, layout: 'rescues/layout')
33
- format = "text/html"
34
- end
35
- render(wrapper.status_code, body, format)
36
- else
37
- raise exception
38
- end
39
- end
40
- end)
41
- end
@@ -1,52 +0,0 @@
1
- # Patch ActionDispatch::DebugExceptions to render HTML for Inertia requests
2
- #
3
- # Original source:
4
- # https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
5
- #
6
-
7
- ActionDispatch::DebugExceptions.class_eval do
8
- prepend(InertiaDebugExceptions = Module.new do
9
- def render_exception(env, exception)
10
- wrapper = ExceptionWrapper.new(env, exception)
11
- log_error(env, wrapper)
12
-
13
- if env['action_dispatch.show_detailed_exceptions']
14
- request = Request.new(env)
15
- traces = wrapper.traces
16
-
17
- trace_to_show = 'Application Trace'
18
- if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
19
- trace_to_show = 'Full Trace'
20
- end
21
-
22
- if source_to_show = traces[trace_to_show].first
23
- source_to_show_id = source_to_show[:id]
24
- end
25
-
26
- template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
27
- request: request,
28
- exception: wrapper.exception,
29
- traces: traces,
30
- show_source_idx: source_to_show_id,
31
- trace_to_show: trace_to_show,
32
- routes_inspector: routes_inspector(exception),
33
- source_extracts: wrapper.source_extracts,
34
- line_number: wrapper.line_number,
35
- file: wrapper.file
36
- )
37
- file = "rescues/#{wrapper.rescue_template}"
38
-
39
- if request.xhr? && !request.headers['X-Inertia'] # <<<< this line is changed only
40
- body = template.render(template: file, layout: false, formats: [:text])
41
- format = "text/plain"
42
- else
43
- body = template.render(template: file, layout: 'rescues/layout')
44
- format = "text/html"
45
- end
46
- render(wrapper.status_code, body, format)
47
- else
48
- raise exception
49
- end
50
- end
51
- end)
52
- end