turbo-rails 0.5.9 → 0.5.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,6 +13,14 @@ module Turbo::Streams::Broadcasts
13
13
  broadcast_action_to *streamables, action: :replace, target: target, **rendering
14
14
  end
15
15
 
16
+ def broadcast_before_to(*streamables, target:, **rendering)
17
+ broadcast_action_to *streamables, action: :before, target: target, **rendering
18
+ end
19
+
20
+ def broadcast_after_to(*streamables, target:, **rendering)
21
+ broadcast_action_to *streamables, action: :after, target: target, **rendering
22
+ end
23
+
16
24
  def broadcast_append_to(*streamables, target:, **rendering)
17
25
  broadcast_action_to *streamables, action: :append, target: target, **rendering
18
26
  end
@@ -32,6 +40,14 @@ module Turbo::Streams::Broadcasts
32
40
  broadcast_action_later_to *streamables, action: :replace, target: target, **rendering
33
41
  end
34
42
 
43
+ def broadcast_before_later_to(*streamables, target:, **rendering)
44
+ broadcast_action_later_to *streamables, action: :before, target: target, **rendering
45
+ end
46
+
47
+ def broadcast_after_later_to(*streamables, target:, **rendering)
48
+ broadcast_action_later_to *streamables, action: :after, target: target, **rendering
49
+ end
50
+
35
51
  def broadcast_append_later_to(*streamables, target:, **rendering)
36
52
  broadcast_action_later_to *streamables, action: :append, target: target, **rendering
37
53
  end
@@ -16,12 +16,16 @@ module Turbo::FramesHelper
16
16
  # <%= turbo_frame_tag "tray", target: "other_tray" %>
17
17
  # # => <turbo-frame id="tray" target="other_tray"></turbo-frame>
18
18
  #
19
+ # <%= turbo_frame_tag "tray", src: tray_path(tray), loading: "lazy" %>
20
+ # # => <turbo-frame id="tray" src="http://example.com/trays/1" loading="lazy"></turbo-frame>
21
+ #
19
22
  # <%= turbo_frame_tag "tray" do %>
20
23
  # <div>My tray frame!</div>
21
24
  # <% end %>
22
25
  # # => <turbo-frame id="tray"><div>My tray frame!</div></turbo-frame>
23
26
  def turbo_frame_tag(id, src: nil, target: nil, **attributes, &block)
24
27
  id = id.respond_to?(:to_key) ? dom_id(id) : id
28
+ src = url_for(src) if src.present?
25
29
 
26
30
  tag.turbo_frame(**attributes.merge(id: id, src: src, target: target).compact, &block)
27
31
  end
@@ -1,5 +1,5 @@
1
1
  module Turbo::StreamsHelper
2
- # Returns a new <tt>Turbo::Streams::TagBuilder</tt> object that accepts stream actions and renders them them as
2
+ # Returns a new <tt>Turbo::Streams::TagBuilder</tt> object that accepts stream actions and renders them as
3
3
  # the template tags needed to send across the wire. This object is automatically yielded to turbo_stream.erb templates.
4
4
  #
5
5
  # When responding to HTTP requests, controllers can declare `turbo_stream` format response templates in that same
@@ -39,7 +39,9 @@ module Turbo::StreamsHelper
39
39
  # The example above will process all turbo streams sent to a stream name like <tt>account:5:entries</tt>
40
40
  # (when Current.account.id = 5). Updates to this stream can be sent like
41
41
  # <tt>entry.broadcast_append_to entry.account, :entries, target: "entries"</tt>.
42
- def turbo_stream_from(*streamables)
43
- tag.turbo_cable_stream_source channel: "Turbo::StreamsChannel", "signed-stream-name": Turbo::StreamsChannel.signed_stream_name(streamables)
42
+ def turbo_stream_from(*streamables, **attributes)
43
+ attributes[:channel] = "Turbo::StreamsChannel"
44
+ attributes[:"signed-stream-name"] = Turbo::StreamsChannel.signed_stream_name(streamables)
45
+ tag.turbo_cable_stream_source(**attributes)
44
46
  end
45
47
  end
@@ -1,15 +1,18 @@
1
1
  let consumer
2
2
 
3
3
  export async function getConsumer() {
4
- if (consumer) return consumer
5
- const { createConsumer } = await import("@rails/actioncable/src")
6
- return setConsumer(createConsumer())
4
+ return consumer || setConsumer(createConsumer().then(setConsumer))
7
5
  }
8
6
 
9
7
  export function setConsumer(newConsumer) {
10
8
  return consumer = newConsumer
11
9
  }
12
10
 
11
+ export async function createConsumer() {
12
+ const { createConsumer } = await import(/* webpackChunkName: "actioncable" */ "@rails/actioncable/src")
13
+ return createConsumer()
14
+ }
15
+
13
16
  export async function subscribeTo(channel, mixin) {
14
17
  const { subscriptions } = await getConsumer()
15
18
  return subscriptions.create(channel, mixin)
@@ -1,5 +1,7 @@
1
1
  # The job that powers all the <tt>broadcast_$action_later</tt> broadcasts available in <tt>Turbo::Streams::Broadcasts</tt>.
2
2
  class Turbo::Streams::ActionBroadcastJob < ActiveJob::Base
3
+ discard_on ActiveJob::DeserializationError
4
+
3
5
  def perform(stream, action:, target:, **rendering)
4
6
  Turbo::StreamsChannel.broadcast_action_to stream, action: action, target: target, **rendering
5
7
  end
@@ -1,6 +1,8 @@
1
1
  # The job that powers the <tt>broadcast_render_later_to</tt> available in <tt>Turbo::Streams::Broadcasts</tt> for rendering
2
2
  # turbo stream templates.
3
3
  class Turbo::Streams::BroadcastJob < ActiveJob::Base
4
+ discard_on ActiveJob::DeserializationError
5
+
4
6
  def perform(stream, **rendering)
5
7
  Turbo::StreamsChannel.broadcast_render_to stream, **rendering
6
8
  end
@@ -39,7 +39,7 @@ module Turbo::Broadcastable
39
39
  module ClassMethods
40
40
  # Configures the model to broadcast creates, updates, and destroys to a stream name derived at runtime by the
41
41
  # <tt>stream</tt> symbol invocation. By default, the creates are appended to a dom id target name derived from
42
- # the model's plural name. The insertion can also be made to be a prepend by overwriting <tt>insertion</tt> and
42
+ # the model's plural name. The insertion can also be made to be a prepend by overwriting <tt>inserts_by</tt> and
43
43
  # the target dom id overwritten by passing <tt>target</tt>. Examples:
44
44
  #
45
45
  # class Message < ApplicationRecord
@@ -52,14 +52,14 @@ module Turbo::Broadcastable
52
52
  # broadcasts_to ->(message) { [ message.board, :messages ] }, inserts_by: :prepend, target: "board_messages"
53
53
  # end
54
54
  def broadcasts_to(stream, inserts_by: :append, target: broadcast_target_default)
55
- after_create_commit -> { broadcast_action_later_to stream.try(:call, self) || send(stream), action: inserts_by, target: target }
55
+ after_create_commit -> { broadcast_action_later_to stream.try(:call, self) || send(stream), action: inserts_by, target: target.try(:call, self) || target }
56
56
  after_update_commit -> { broadcast_replace_later_to stream.try(:call, self) || send(stream) }
57
57
  after_destroy_commit -> { broadcast_remove_to stream.try(:call, self) || send(stream) }
58
58
  end
59
59
 
60
60
  # Same as <tt>#broadcasts_to</tt>, but the designated stream is automatically set to the current model.
61
61
  def broadcasts(inserts_by: :append, target: broadcast_target_default)
62
- after_create_commit -> { broadcast_action_later action: inserts_by, target: target }
62
+ after_create_commit -> { broadcast_action_later action: inserts_by, target: target.try(:call, self) || target }
63
63
  after_update_commit -> { broadcast_replace_later }
64
64
  after_destroy_commit -> { broadcast_remove }
65
65
  end
@@ -103,6 +103,38 @@ module Turbo::Broadcastable
103
103
  broadcast_replace_to self, **rendering
104
104
  end
105
105
 
106
+ # Insert a rendering of this broadcastable model before the target identified by it's dom id passed as <tt>target</tt>
107
+ # for subscribers of the stream name identified by the passed <tt>streamables</tt>. The rendering parameters can be set by
108
+ # appending named arguments to the call. Examples:
109
+ #
110
+ # # Sends <turbo-stream action="before" target="clearance_5"><template><div id="clearance_4">My Clearance</div></template></turbo-stream>
111
+ # # to the stream named "identity:2:clearances"
112
+ # clearance.broadcast_before_to examiner.identity, :clearances, target: "clearance_5"
113
+ #
114
+ # # Sends <turbo-stream action="before" target="clearance_5"><template><div id="clearance_4">Other partial</div></template></turbo-stream>
115
+ # # to the stream named "identity:2:clearances"
116
+ # clearance.broadcast_before_to examiner.identity, :clearances, target: "clearance_5",
117
+ # partial: "clearances/other_partial", locals: { a: 1 }
118
+ def broadcast_before_to(*streamables, target:, **rendering)
119
+ Turbo::StreamsChannel.broadcast_before_to *streamables, target: target, **broadcast_rendering_with_defaults(rendering)
120
+ end
121
+
122
+ # Insert a rendering of this broadcastable model after the target identified by it's dom id passed as <tt>target</tt>
123
+ # for subscribers of the stream name identified by the passed <tt>streamables</tt>. The rendering parameters can be set by
124
+ # appending named arguments to the call. Examples:
125
+ #
126
+ # # Sends <turbo-stream action="after" target="clearance_5"><template><div id="clearance_6">My Clearance</div></template></turbo-stream>
127
+ # # to the stream named "identity:2:clearances"
128
+ # clearance.broadcast_after_to examiner.identity, :clearances, target: "clearance_5"
129
+ #
130
+ # # Sends <turbo-stream action="after" target="clearance_5"><template><div id="clearance_6">Other partial</div></template></turbo-stream>
131
+ # # to the stream named "identity:2:clearances"
132
+ # clearance.broadcast_after_to examiner.identity, :clearances, target: "clearance_5",
133
+ # partial: "clearances/other_partial", locals: { a: 1 }
134
+ def broadcast_after_to(*streamables, target:, **rendering)
135
+ Turbo::StreamsChannel.broadcast_after_to *streamables, target: target, **broadcast_rendering_with_defaults(rendering)
136
+ end
137
+
106
138
  # Append a rendering of this broadcastable model to the target identified by it's dom id passed as <tt>target</tt>
107
139
  # for subscribers of the stream name identified by the passed <tt>streamables</tt>. The rendering parameters can be set by
108
140
  # appending named arguments to the call. Examples:
@@ -140,7 +172,7 @@ module Turbo::Broadcastable
140
172
  Turbo::StreamsChannel.broadcast_prepend_to *streamables, target: target, **broadcast_rendering_with_defaults(rendering)
141
173
  end
142
174
 
143
- # Same as <tt>#broadcast_append_to</tt>, but the designated stream is automatically set to the current model.
175
+ # Same as <tt>#broadcast_prepend_to</tt>, but the designated stream is automatically set to the current model.
144
176
  def broadcast_prepend(target: broadcast_target_default, **rendering)
145
177
  broadcast_prepend_to self, target: target, **rendering
146
178
  end
@@ -190,7 +222,7 @@ module Turbo::Broadcastable
190
222
  broadcast_prepend_later_to self, target: target, **rendering
191
223
  end
192
224
 
193
- # Same as <tt>broadcast_action_later_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
225
+ # Same as <tt>broadcast_action_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
194
226
  def broadcast_action_later_to(*streamables, action:, target: broadcast_target_default, **rendering)
195
227
  Turbo::StreamsChannel.broadcast_action_later_to(*streamables, action: action, target: target, **broadcast_rendering_with_defaults(rendering))
196
228
  end
@@ -219,7 +251,7 @@ module Turbo::Broadcastable
219
251
  broadcast_render_later_to self, **rendering
220
252
  end
221
253
 
222
- # Same as <tt>broadcast_prepend_to</tt> but run with the added option of naming the stream using the passed
254
+ # Same as <tt>broadcast_render_later</tt> but run with the added option of naming the stream using the passed
223
255
  # <tt>streamables</tt>.
224
256
  def broadcast_render_later_to(*streamables, **rendering)
225
257
  Turbo::StreamsChannel.broadcast_render_later_to *streamables, **broadcast_rendering_with_defaults(rendering)
@@ -233,7 +265,7 @@ module Turbo::Broadcastable
233
265
 
234
266
  def broadcast_rendering_with_defaults(options)
235
267
  options.tap do |o|
236
- o[:locals] = (o[:locals] || {}).reverse_merge!(model_name.singular.to_sym => self)
268
+ o[:object] ||= self
237
269
  o[:partial] ||= to_partial_path
238
270
  end
239
271
  end
@@ -53,6 +53,32 @@ class Turbo::Streams::TagBuilder
53
53
  action :replace, target, content, **rendering, &block
54
54
  end
55
55
 
56
+ # Insert the <tt>content</tt> passed in, a rendering result determined by the <tt>rendering</tt> keyword arguments,
57
+ # the content in the block, or the rendering of the target as a record before the <tt>target</tt> in the dom. Examples:
58
+ #
59
+ # <%= turbo_stream.before "clearance_5", "<div id='clearance_4'>Insert before the dom target identified by clearance_5</div>" %>
60
+ # <%= turbo_stream.before clearance %>
61
+ # <%= turbo_stream.before clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
62
+ # <%= turbo_stream.before "clearance_5" do %>
63
+ # <div id='clearance_4'>Insert before the dom target identified by clearance_5</div>
64
+ # <% end %>
65
+ def before(target, content = nil, **rendering, &block)
66
+ action :before, target, content, **rendering, &block
67
+ end
68
+
69
+ # Insert the <tt>content</tt> passed in, a rendering result determined by the <tt>rendering</tt> keyword arguments,
70
+ # the content in the block, or the rendering of the target as a record after the <tt>target</tt> in the dom. Examples:
71
+ #
72
+ # <%= turbo_stream.after "clearance_5", "<div id='clearance_6'>Insert after the dom target identified by clearance_5</div>" %>
73
+ # <%= turbo_stream.after clearance %>
74
+ # <%= turbo_stream.after clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
75
+ # <%= turbo_stream.after "clearance_5" do %>
76
+ # <div id='clearance_6'>Insert after the dom target identified by clearance_5</div>
77
+ # <% end %>
78
+ def after(target, content = nil, **rendering, &block)
79
+ action :after, target, content, **rendering, &block
80
+ end
81
+
56
82
  # Update the <tt>target</tt> in the dom with the either the <tt>content</tt> passed in or a rendering result determined
57
83
  # by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
58
84
  #
@@ -19,12 +19,7 @@ if APPLICATION_LAYOUT_PATH.exist?
19
19
  end
20
20
  else
21
21
  say "Default application.html.erb is missing!", :red
22
-
23
- if APPLICATION_LAYOUT_PATH.read =~ /stimulus/
24
- say %( Add <%= javascript_include_tag("turbo", type: "module-shim") %> and <%= yield :head %> within the <head> tag after Stimulus includes in your custom layout.)
25
- else
26
- say %( Add <%= javascript_include_tag("turbo", type: "module") %> and <%= yield :head %> within the <head> tag in your custom layout.)
27
- end
22
+ say %( Add <%= javascript_include_tag("turbo", type: "module-shim") %> and <%= yield :head %> within the <head> tag after Stimulus includes in your custom layout.)
28
23
  end
29
24
 
30
25
  say "Enable redis in bundle"
@@ -1,16 +1,17 @@
1
1
  # Some Rails versions use commonJS(require) others use ESM(import).
2
2
  TURBOLINKS_REGEX = /(import .* from "turbolinks".*\n|require\("turbolinks"\).*\n)/.freeze
3
+ ACTIVE_STORAGE_REGEX = /(import.*ActiveStorage|require.*@rails\/activestorage.*)/.freeze
3
4
 
4
5
  abort "❌ Webpacker not found. Exiting." unless defined?(Webpacker::Engine)
5
6
 
6
7
  say "Install Turbo"
7
8
  run "yarn add @hotwired/turbo-rails"
8
- insert_into_file "#{Webpacker.config.source_entry_path}/application.js", "import \"@hotwired/turbo-rails\"\n", before: /import.*ActiveStorage/
9
+ insert_into_file "#{Webpacker.config.source_entry_path}/application.js", "import \"@hotwired/turbo-rails\"\n", before: ACTIVE_STORAGE_REGEX
9
10
 
10
11
  say "Remove Turbolinks"
11
- gsub_file 'Gemfile', /gem 'turbolinks'.*/, ''
12
- run "bin/bundle", capture: true
13
- run "bin/yarn remove turbolinks"
12
+ run "#{RbConfig.ruby} bin/bundle remove turbolinks"
13
+ run "#{RbConfig.ruby} bin/bundle", capture: true
14
+ run "#{RbConfig.ruby} bin/yarn remove turbolinks"
14
15
  gsub_file "#{Webpacker.config.source_entry_path}/application.js", TURBOLINKS_REGEX, ''
15
16
  gsub_file "#{Webpacker.config.source_entry_path}/application.js", /Turbolinks.start.*\n/, ''
16
17
 
data/lib/turbo/engine.rb CHANGED
@@ -16,13 +16,17 @@ module Turbo
16
16
  #{root}/app/jobs
17
17
  )
18
18
 
19
+ initializer "turbo.no_action_cable" do
20
+ Rails.autoloaders.once.do_not_eager_load(Dir["#{root}/app/channels/turbo/*_channel.rb"]) unless defined?(ActionCable)
21
+ end
22
+
19
23
  initializer "turbo.assets" do
20
24
  if Rails.application.config.respond_to?(:assets)
21
25
  Rails.application.config.assets.precompile += %w( turbo )
22
26
  end
23
27
  end
24
28
 
25
- initializer "turbo.helpers" do
29
+ initializer "turbo.helpers", before: :load_config_initializers do
26
30
  ActiveSupport.on_load(:action_controller_base) do
27
31
  include Turbo::Streams::TurboStreamsTagBuilder, Turbo::Frames::FrameRequest, Turbo::Native::Navigation
28
32
  helper Turbo::Engine.helpers
@@ -7,14 +7,13 @@ module Turbo
7
7
  delegate :dom_id, :dom_class, to: ActionView::RecordIdentifier
8
8
  end
9
9
 
10
- def assert_turbo_stream(action:, target: nil, &block)
11
- assert_response :ok
10
+ def assert_turbo_stream(action:, target: nil, status: :ok, &block)
11
+ assert_response status
12
12
  assert_equal Mime[:turbo_stream], response.media_type
13
13
  assert_select %(turbo-stream[action="#{action}"][target="#{target.respond_to?(:to_key) ? dom_id(target) : target}"]), count: 1, &block
14
14
  end
15
15
 
16
16
  def assert_no_turbo_stream(action:, target: nil)
17
- assert_response :ok
18
17
  assert_equal Mime[:turbo_stream], response.media_type
19
18
  assert_select %(turbo-stream[action="#{action}"][target="#{target.respond_to?(:to_key) ? dom_id(target) : target}"]), count: 0
20
19
  end
data/lib/turbo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Turbo
2
- VERSION = "0.5.9"
2
+ VERSION = "0.5.10"
3
3
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.9
4
+ version: 0.5.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
8
8
  - Javan Mahkmali
9
9
  - David Heinemeier Hansson
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-01-30 00:00:00.000000000 Z
13
+ date: 2021-06-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -26,7 +26,7 @@ dependencies:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: 6.0.0
29
- description:
29
+ description:
30
30
  email: david@loudthinking.com
31
31
  executables: []
32
32
  extensions: []
@@ -67,7 +67,7 @@ homepage: https://github.com/hotwired/turbo-rails
67
67
  licenses:
68
68
  - MIT
69
69
  metadata: {}
70
- post_install_message:
70
+ post_install_message:
71
71
  rdoc_options: []
72
72
  require_paths:
73
73
  - lib
@@ -82,8 +82,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  requirements: []
85
- rubygems_version: 3.1.2
86
- signing_key:
85
+ rubygems_version: 3.1.4
86
+ signing_key:
87
87
  specification_version: 4
88
88
  summary: The speed of a single-page web application without having to write any JavaScript.
89
89
  test_files: []