turbo_form 0.8.0 → 0.9.0

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: 69e93adb63b8efad18d18aa5009294ecf46dff732a835677016787a498a359fe
4
- data.tar.gz: 8058b55a07707691cd9bb2770339f2685ca4c13f104cd97db01aeeef184326bd
3
+ metadata.gz: cb59d187ec74c47b4ed52d8067f54faa85997be5e5551d22771b12c4224017fe
4
+ data.tar.gz: 376442d6aaf5c3d403355bc2ba1f4c653d4794fdd5b22288aa3650c0a132e3b2
5
5
  SHA512:
6
- metadata.gz: 641956f04889ecb24a6744d65f9a397e75dfa97ac5fcf57847dab4c41c06bf641268b0e620f4b9e8e1cdf865e23eaf97606a286b7db8eabc1d27d31a02707381
7
- data.tar.gz: 36036dda2b7c129b9a4d704695d849049bcafbe4f5fec2b3690b2709e2e98dcaaaf2ffab4ce8c438712df1b6ea78bec0d29b08d25a9024c56ccd9d98c299d18e
6
+ metadata.gz: 344e3f436b6fa24fcbbcd6f65e04a0212ff588b77766f121e7941decfa4ad4bcaa2ef181cc295c60a4eb80af1b7f14390387c74ced7c8ac106c67de1ffca7bdb
7
+ data.tar.gz: 5eb9d4403823fe67d7eaaf438d429e46d28c33e6163fd144b8f7aecd4a3e4ea478bd9c59ce066196da8bb2b5c67c40588000361b271339ea50c3d4dbf9b9e7ec
data/README.md CHANGED
@@ -36,21 +36,12 @@ Then run the installer:
36
36
  rails generate turbo_form:install
37
37
  ```
38
38
 
39
- It includes `TurboForm::Controller` in your ApplicationController and declares
40
- the route concern:
41
-
42
- ```ruby
43
- class ApplicationController < ActionController::Base
44
- include TurboForm::Controller
45
- end
46
- ```
47
-
48
- ```ruby
49
- concern :turbo_form, TurboForm::Routes
50
- ```
39
+ It imports the script into `app/javascript/application.js`, adding the npm
40
+ package first if your app bundles with esbuild, Vite, Bun or webpack; see
41
+ [JavaScript](#javascript) for doing that by hand.
51
42
 
52
- Draw the concern on each resource with a dynamic form — the installer leaves
53
- which ones to you:
43
+ The engine does the rest. Draw the `:turbo_form` route concern on each resource
44
+ with a dynamic form:
54
45
 
55
46
  ```ruby
56
47
  resources :widgets, concerns: :turbo_form
@@ -58,11 +49,8 @@ resources :widgets, concerns: :turbo_form
58
49
 
59
50
  It draws a PATCH beside whichever of `new` and `edit` the resource has, so
60
51
  `resources :widgets, only: %i[new create], concerns: :turbo_form` gets only the
61
- one for `new`.
62
-
63
- It also imports the script into `app/javascript/application.js`, adding the npm
64
- package first if your app bundles with esbuild, Vite, Bun or webpack; see
65
- [JavaScript](#javascript) for doing that by hand.
52
+ one for `new`. Every controller inheriting from `ActionController::Base` already
53
+ knows how to answer it.
66
54
 
67
55
  ## The options
68
56
 
@@ -70,7 +58,7 @@ package first if your app bundles with esbuild, Vite, Bun or webpack; see
70
58
 
71
59
  `dynamic: true` makes the form dynamic: a trigger sends it to the `new` or `edit`
72
60
  page of its model — `edit` once the record is saved — which is where
73
- `TurboForm::Routes` listens.
61
+ the route concern listens.
74
62
 
75
63
  ### `dynamic_trigger:` on a field
76
64
 
@@ -2,9 +2,8 @@ require 'rails/generators'
2
2
 
3
3
  module TurboForm
4
4
  module Generators
5
- # Every app gets TurboForm::Controller, the route concern its resources opt
6
- # into and an import of the script. On importmap-rails the engine pins the
7
- # script itself; bundled apps get the npm package to import instead.
5
+ # Every app gets an import of the script. On importmap-rails the engine pins
6
+ # the script itself; bundled apps get the npm package to import instead.
8
7
  class InstallGenerator < Rails::Generators::Base
9
8
  LOCKFILES = {
10
9
  'yarn.lock' => 'yarn add', 'pnpm-lock.yaml' => 'pnpm add',
@@ -14,23 +13,11 @@ module TurboForm
14
13
  ENTRYPOINT = 'app/javascript/application.js'
15
14
 
16
15
  def install
17
- include_controller
18
- declare_route_concern
19
16
  install_package unless importmap?
20
17
  import_script
21
18
  end
22
19
 
23
20
  private
24
- def include_controller
25
- inject_into_class 'app/controllers/application_controller.rb', 'ApplicationController', " include TurboForm::Controller\n"
26
- end
27
-
28
- # Declared once, drawn on no resource: which forms are dynamic is the
29
- # app's call, one `concerns: :turbo_form` at a time.
30
- def declare_route_concern
31
- route 'concern :turbo_form, TurboForm::Routes'
32
- end
33
-
34
21
  def importmap? = Rails.root.join('config/importmap.rb').exist?
35
22
 
36
23
  def install_package
@@ -1,5 +1,5 @@
1
1
  module TurboForm
2
- # Included into the host's ApplicationController. A request that
2
+ # Included into ActionController::Base by the engine. A request that
3
3
  # TurboForm::Routes marks runs `new` or `edit` as usual, callbacks and all,
4
4
  # then assigns the form to what the action built just before it renders --
5
5
  # implicitly, or with its own `render layout: 'panel'`.
@@ -1,6 +1,7 @@
1
1
  require 'turbo-rails'
2
2
  require 'turbo_form/form_helper'
3
3
  require 'turbo_form/form_builder'
4
+ require 'turbo_form/select_renderer'
4
5
  require 'turbo_form/routes'
5
6
  require 'turbo_form/controller'
6
7
 
@@ -50,6 +51,14 @@ module TurboForm
50
51
  end
51
52
  end
52
53
 
54
+ initializer 'turbo_form.controller' do
55
+ ActiveSupport.on_load(:action_controller_base) { include TurboForm::Controller }
56
+ end
57
+
58
+ initializer 'turbo_form.routes' do
59
+ ActionDispatch::Routing::Mapper.prepend(TurboForm::Routes::Declared)
60
+ end
61
+
53
62
  # Deliberately eager rather than `ActiveSupport.on_load(:action_view)`: that
54
63
  # hook doesn't fire until Action View is first loaded, which in an app that
55
64
  # isn't eager loading is partway through rendering the first view -- late
@@ -59,6 +68,7 @@ module TurboForm
59
68
 
60
69
  ActionView::Helpers::FormHelper.prepend(TurboForm::FormHelper)
61
70
  ActionView::Helpers::FormBuilder.prepend(TurboForm::FormBuilder)
71
+ ActionView::Helpers::Tags::SelectRenderer.prepend(TurboForm::SelectRenderer)
62
72
  end
63
73
  end
64
74
  end
@@ -78,9 +78,11 @@ module TurboForm
78
78
  [ options.except(*DYNAMIC_OPTIONS), absorb_trigger(html_options.merge(options.slice(*DYNAMIC_OPTIONS))) ]
79
79
  end
80
80
 
81
+ def absorb_trigger(attributes) = FormBuilder.absorb_trigger(attributes, @template)
82
+
81
83
  # `dynamic_action:` makes a trigger of its own, on the default event unless
82
84
  # `dynamic_trigger:` names one. It takes whatever `url_for` does.
83
- def absorb_trigger(attributes)
85
+ def self.absorb_trigger(attributes, template)
84
86
  return attributes unless attributes.keys.intersect?(DYNAMIC_OPTIONS)
85
87
 
86
88
  trigger, action = attributes.values_at(*DYNAMIC_OPTIONS)
@@ -88,12 +90,12 @@ module TurboForm
88
90
  trigger ||= action.present?
89
91
  return attributes unless trigger
90
92
 
91
- attributes.merge(data: { **attributes[:data].to_h, turbo_form_trigger: trigger_event(trigger), turbo_form_action: (@template.url_for(action) if action) })
93
+ attributes.merge(data: { **attributes[:data].to_h, turbo_form_trigger: trigger_event(trigger), turbo_form_action: (template.url_for(action) if action) })
92
94
  end
93
95
 
94
96
  # Left blank for `true`, which the script reads as the element's own
95
97
  # default: `change` for a select, `input` for a text field, `click` for a
96
98
  # button.
97
- def trigger_event(trigger) = trigger == true ? '' : trigger.to_s
99
+ def self.trigger_event(trigger) = trigger == true ? '' : trigger.to_s
98
100
  end
99
101
  end
@@ -3,7 +3,6 @@ module TurboForm
3
3
  # and `edit` it has, at the same paths and onto the same actions, marked so the
4
4
  # controller renders them from what the form currently holds.
5
5
  #
6
- # concern :turbo_form, TurboForm::Routes
7
6
  # resources :widgets, concerns: :turbo_form
8
7
  module Routes
9
8
  def self.call(mapper, _options = {})
@@ -12,5 +11,15 @@ module TurboForm
12
11
  mapper.new { mapper.patch :new, as: nil, defaults: { dynamic_form: true } } if actions.include?(:new)
13
12
  mapper.patch :edit, on: :member, as: nil, defaults: { dynamic_form: true } if actions.include?(:edit)
14
13
  end
14
+
15
+ # Rails keeps concerns per Mapper, and builds a fresh one for every `draw`,
16
+ # `prepend` and `append`, so declaring it once from the engine can't reach
17
+ # them all. An app's own `concern :turbo_form` still replaces this one.
18
+ module Declared
19
+ def initialize(...)
20
+ super
21
+ concern :turbo_form, TurboForm::Routes
22
+ end
23
+ end
15
24
  end
16
25
  end
@@ -0,0 +1,11 @@
1
+ module TurboForm
2
+ # Prepended onto ActionView::Helpers::Tags::SelectRenderer, which every select
3
+ # tag renders through -- including those of builder methods other gems add,
4
+ # like country_select's, which hand their html_options straight to the tag.
5
+ module SelectRenderer
6
+ private
7
+ def select_content_tag(option_tags, options, html_options)
8
+ super(option_tags, options, FormBuilder.absorb_trigger(html_options.symbolize_keys, @template_object))
9
+ end
10
+ end
11
+ end
@@ -1,13 +1,14 @@
1
1
  module TurboForm::SystemTestHelper
2
- # Waits for a dynamic form to finish reloading the page.
2
+ # Waits for a dynamic form to finish reloading the page. Reads <html> from the
3
+ # document, so it works inside `within` too.
3
4
  #
4
5
  # expect_dynamic_form_request { select "Bourbon", from: "Category" }
5
6
  # select "Barrel Aged", from: "Flavor"
6
7
  def expect_dynamic_form_request
7
- completed = page.find('html')['data-turbo-form-visits'].to_i + 1
8
+ completed = page.document.find('html')['data-turbo-form-visits'].to_i + 1
8
9
 
9
10
  yield
10
11
 
11
- page.assert_selector "html[data-turbo-form-visits='#{completed}']"
12
+ page.document.assert_selector "html[data-turbo-form-visits='#{completed}']"
12
13
  end
13
14
  end
@@ -1,3 +1,3 @@
1
1
  module TurboForm
2
- VERSION = '0.8.0'
2
+ VERSION = '0.9.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Cohen
@@ -85,6 +85,7 @@ files:
85
85
  - lib/turbo_form/form_builder.rb
86
86
  - lib/turbo_form/form_helper.rb
87
87
  - lib/turbo_form/routes.rb
88
+ - lib/turbo_form/select_renderer.rb
88
89
  - lib/turbo_form/system_test_helper.rb
89
90
  - lib/turbo_form/version.rb
90
91
  homepage: https://github.com/outlawandy/turbo_form
@@ -108,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  requirements: []
111
- rubygems_version: 4.0.20
112
+ rubygems_version: 4.0.16
112
113
  specification_version: 4
113
114
  summary: Turbo-Stream backed dynamic forms, by convention.
114
115
  test_files: []