Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
#210 added the ability to set `targets` on a stream tag. But that doesn't work nicely with the `Broadcastable` helper methods. Currently you have to do this to target some `targets`:

```ruby
after_update_commit -> { broadcast_update_to self, target: nil, targets: ".class_name" }
```

This PR improves things so that you don't need to provide `target: nil` anymore.

--

This PR is a continuation of the work made by @ghiculescu at PR turbo-rails#408
  • Loading branch information
JuannFerrari committed Nov 9, 2023
1 parent e44b6a9 commit 5d6e604
Showing 1 changed file with 48 additions and 38 deletions.
86 changes: 48 additions & 38 deletions app/models/concerns/turbo/broadcastable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,13 @@ def broadcast_target_default
#
# # Sends <turbo-stream action="remove" target="clearance_5"></turbo-stream> to the stream named "identity:2:clearances"
# clearance.broadcast_remove_to examiner.identity, :clearances
def broadcast_remove_to(*streamables, target: self)
Turbo::StreamsChannel.broadcast_remove_to(*streamables, target: target)
def broadcast_remove_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_remove_to(*streamables, **extract_options_and_add_target(rendering, target: self))
end

# Same as <tt>#broadcast_remove_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_remove
broadcast_remove_to self
def broadcast_remove(**rendering)
broadcast_remove_to self, **rendering
end

# Replace this broadcastable model in the dom for subscribers of the stream name identified by the passed
Expand All @@ -143,7 +143,7 @@ def broadcast_remove
# # to the stream named "identity:2:clearances"
# clearance.broadcast_replace_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }
def broadcast_replace_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_replace_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
Turbo::StreamsChannel.broadcast_replace_to(*streamables, **extract_options_and_add_target(rendering, target: self))
end

# Same as <tt>#broadcast_replace_to</tt>, but the designated stream is automatically set to the current model.
Expand All @@ -162,7 +162,7 @@ def broadcast_replace(**rendering)
# # to the stream named "identity:2:clearances"
# clearance.broadcast_update_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }
def broadcast_update_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_update_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
Turbo::StreamsChannel.broadcast_update_to(*streamables, **extract_options_and_add_target(rendering, target: self))
end

# Same as <tt>#broadcast_update_to</tt>, but the designated stream is automatically set to the current model.
Expand All @@ -182,8 +182,10 @@ def broadcast_update(**rendering)
# # to the stream named "identity:2:clearances"
# clearance.broadcast_before_to examiner.identity, :clearances, target: "clearance_5",
# partial: "clearances/other_partial", locals: { a: 1 }
def broadcast_before_to(*streamables, target:, **rendering)
Turbo::StreamsChannel.broadcast_before_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
def broadcast_before_to(*streamables, target: nil, targets: nil, **rendering)
raise ArgumentError, "at least one of target or targets is required" unless target || targets

Turbo::StreamsChannel.broadcast_before_to(*streamables, **extract_options_and_add_target(rendering.merge(target: target, targets: targets)))
end

# Insert a rendering of this broadcastable model after the target identified by it's dom id passed as <tt>target</tt>
Expand All @@ -198,8 +200,10 @@ def broadcast_before_to(*streamables, target:, **rendering)
# # to the stream named "identity:2:clearances"
# clearance.broadcast_after_to examiner.identity, :clearances, target: "clearance_5",
# partial: "clearances/other_partial", locals: { a: 1 }
def broadcast_after_to(*streamables, target:, **rendering)
Turbo::StreamsChannel.broadcast_after_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
def broadcast_after_to(*streamables, target: nil, targets: nil, **rendering)
raise ArgumentError, "at least one of target or targets is required" unless target || targets

Turbo::StreamsChannel.broadcast_after_to(*streamables, **extract_options_and_add_target(rendering.merge(target: target, targets: targets)))
end

# Append a rendering of this broadcastable model to the target identified by it's dom id passed as <tt>target</tt>
Expand All @@ -214,13 +218,13 @@ def broadcast_after_to(*streamables, target:, **rendering)
# # to the stream named "identity:2:clearances"
# clearance.broadcast_append_to examiner.identity, :clearances, target: "clearances",
# partial: "clearances/other_partial", locals: { a: 1 }
def broadcast_append_to(*streamables, target: broadcast_target_default, **rendering)
Turbo::StreamsChannel.broadcast_append_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
def broadcast_append_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_append_to(*streamables, **extract_options_and_add_target(rendering))
end

# Same as <tt>#broadcast_append_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_append(target: broadcast_target_default, **rendering)
broadcast_append_to self, target: target, **rendering
def broadcast_append(**rendering)
broadcast_append_to self, **rendering
end

# Prepend a rendering of this broadcastable model to the target identified by it's dom id passed as <tt>target</tt>
Expand All @@ -235,33 +239,33 @@ def broadcast_append(target: broadcast_target_default, **rendering)
# # to the stream named "identity:2:clearances"
# clearance.broadcast_prepend_to examiner.identity, :clearances, target: "clearances",
# partial: "clearances/other_partial", locals: { a: 1 }
def broadcast_prepend_to(*streamables, target: broadcast_target_default, **rendering)
Turbo::StreamsChannel.broadcast_prepend_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
def broadcast_prepend_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_prepend_to(*streamables, **extract_options_and_add_target(rendering))
end

# Same as <tt>#broadcast_prepend_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_prepend(target: broadcast_target_default, **rendering)
broadcast_prepend_to self, target: target, **rendering
def broadcast_prepend(**rendering)
broadcast_prepend_to self, **rendering
end

# Broadcast a named <tt>action</tt>, allowing for dynamic dispatch, instead of using the concrete action methods. Examples:
#
# # Sends <turbo-stream action="prepend" target="clearances"><template><div id="clearance_5">My Clearance</div></template></turbo-stream>
# # to the stream named "identity:2:clearances"
# clearance.broadcast_action_to examiner.identity, :clearances, action: :prepend, target: "clearances"
def broadcast_action_to(*streamables, action:, target: broadcast_target_default, attributes: {}, **rendering)
Turbo::StreamsChannel.broadcast_action_to(*streamables, action: action, target: target, attributes: attributes, **broadcast_rendering_with_defaults(rendering))
def broadcast_action_to(*streamables, action:, **rendering)
Turbo::StreamsChannel.broadcast_action_to(*streamables, action: action, **extract_options_and_add_target(rendering))
end

# Same as <tt>#broadcast_action_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_action(action, target: broadcast_target_default, attributes: {}, **rendering)
broadcast_action_to self, action: action, target: target, attributes: attributes, **rendering
def broadcast_action(action, **rendering)
broadcast_action_to self, action: action, **rendering
end


# Same as <tt>broadcast_replace_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
def broadcast_replace_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_replace_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
Turbo::StreamsChannel.broadcast_replace_later_to(*streamables, **extract_options_and_add_target(rendering, target: self))
end

# Same as <tt>#broadcast_replace_later_to</tt>, but the designated stream is automatically set to the current model.
Expand All @@ -271,7 +275,7 @@ def broadcast_replace_later(**rendering)

# Same as <tt>broadcast_update_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
def broadcast_update_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_update_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
Turbo::StreamsChannel.broadcast_update_later_to(*streamables, **extract_options_and_add_target(rendering, target: self))
end

# Same as <tt>#broadcast_update_later_to</tt>, but the designated stream is automatically set to the current model.
Expand All @@ -280,33 +284,33 @@ def broadcast_update_later(**rendering)
end

# Same as <tt>broadcast_append_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
def broadcast_append_later_to(*streamables, target: broadcast_target_default, **rendering)
Turbo::StreamsChannel.broadcast_append_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
def broadcast_append_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_append_later_to(*streamables, **extract_options_and_add_target(rendering))
end

# Same as <tt>#broadcast_append_later_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_append_later(target: broadcast_target_default, **rendering)
broadcast_append_later_to self, target: target, **rendering
def broadcast_append_later(**rendering)
broadcast_append_later_to self, **rendering
end

# Same as <tt>broadcast_prepend_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
def broadcast_prepend_later_to(*streamables, target: broadcast_target_default, **rendering)
Turbo::StreamsChannel.broadcast_prepend_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
def broadcast_prepend_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_prepend_later_to(*streamables, **extract_options_and_add_target(rendering))
end

# Same as <tt>#broadcast_prepend_later_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_prepend_later(target: broadcast_target_default, **rendering)
broadcast_prepend_later_to self, target: target, **rendering
def broadcast_prepend_later(**rendering)
broadcast_prepend_later_to self, **rendering
end

# Same as <tt>broadcast_action_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
def broadcast_action_later_to(*streamables, action:, target: broadcast_target_default, attributes: {}, **rendering)
Turbo::StreamsChannel.broadcast_action_later_to(*streamables, action: action, target: target, attributes: attributes, **broadcast_rendering_with_defaults(rendering))
def broadcast_action_later_to(*streamables, action:, **rendering)
Turbo::StreamsChannel.broadcast_action_later_to(*streamables, action: action, **extract_options_and_add_target(rendering))
end

# Same as <tt>#broadcast_action_later_to</tt>, but the designated stream is automatically set to the current model.
def broadcast_action_later(action:, target: broadcast_target_default, attributes: {}, **rendering)
broadcast_action_later_to self, action: action, target: target, attributes: attributes, **rendering
def broadcast_action_later(action:, **rendering)
broadcast_action_later_to self, action: action, **rendering
end

# Render a turbo stream template with this broadcastable model passed as the local variable. Example:
Expand Down Expand Up @@ -337,7 +341,7 @@ def broadcast_render(**rendering)
# desireable for model callbacks, certainly not if those callbacks are inside of a transaction. Most of the time you should
# be using `broadcast_render_later_to`, unless you specifically know why synchronous rendering is needed.
def broadcast_render_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_render_to(*streamables, **broadcast_rendering_with_defaults(rendering))
Turbo::StreamsChannel.broadcast_render_to(*streamables, **extract_options_and_add_target(rendering))
end

# Same as <tt>broadcast_action_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
Expand All @@ -348,7 +352,7 @@ def broadcast_render_later(**rendering)
# Same as <tt>broadcast_render_later</tt> but run with the added option of naming the stream using the passed
# <tt>streamables</tt>.
def broadcast_render_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **broadcast_rendering_with_defaults(rendering))
Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **extract_options_and_add_target(rendering))
end


Expand All @@ -357,6 +361,12 @@ def broadcast_target_default
self.class.broadcast_target_default
end

def extract_options_and_add_target(rendering, target: broadcast_target_default)
broadcast_rendering_with_defaults(rendering).tap do |options|
options[:target] = target if !options.key?(:target) && !options.key?(:targets)
end
end

def broadcast_rendering_with_defaults(options)
options.tap do |o|
# Add the current instance into the locals with the element name (which is the un-namespaced name)
Expand Down

0 comments on commit 5d6e604

Please sign in to comment.