⬆️ StimulusReflex is for sending commands. 📡 ⬇️ CableReady is for receiving updates. 👽
CableReady has 36 operations for changing every aspect of your page, and you can define your own. It can emit events, set cookies, make you breakfast and call your parents (Twilio fees are not included.)
StimulusReflex uses CableReady's
morphfor Page Morphs and some Selector Morphs,
inner_htmlfor Selector Morphs that don't use
dispatch_eventfor Nothing Morphs, as well as aborted/halted Reflexes and sending errors that occur in a Reflex action.
The reason some Selector morphs are sent via
inner_htmlis that the content you send to replace your existing DOM elements has to match up. If you replace an element with something completely different,
morphjust won't work. You can read all about this in the Morphing Sanity Checklist.
It's common for developers to use CableReady inside a Reflex action for all sorts of things, especially initiating client-side events which can be picked up by Stimulus controllers. Another pattern is to use Nothing Morphs that call CableReady operations.
Inside of a Reflex class,
CableReady::Broadcasteris already included, giving you access to the
dom_idhelper and a special version of the
cable_readymethod. If you call
cable_readyin a Reflex action without specifying a stream or resource - in other words, no brackets - CableReady will piggyback on the StimulusReflex ActionCable channel.
This means you can automatically target the current user, and if you're only ever targeting the current user, you don't need to set up a channel for CableReady at all.
class ExampleReflex < ApplicationReflex
cable_ready.console_log(message: "Cable Ready rocks!").broadcast
This is just like calling
stream_nameis the internal variable StimulusReflex uses to hold the stream identifier it uses to send updates to the current user.
The only constraint imposed upon use of the special
cable_readymethod is that
broadcastmethods must appear at the end of a method chain. This is because calling
cable_ready.broadcastwithout queueing any additional operations already has a function when using CableReady; it tells CableReady to broadcast any enqueued operations on all string-based identifier channels.
You can still use CableReady "normally" inside of a Reflex, if you need to broadcast to more than just the current user. Just call
cable_readywith a stream identifier in brackets.
Since StimulusReflex uses CableReady's
inner_htmloperations, you might be wondering when or if to just use CableReady operations directly instead of calling StimulusReflex's
The simple answer is that you should use StimulusReflex when you need life-cycle management; callbacks, events and promises. Reflexes have a transactional life-cycle, where each one is assigned a UUID and the client will have the opportunity to respond if something goes wrong.
CableReady operations raise their own events, but StimulusReflex won't know if they are successful or not. Any CableReady operations you broadcast in a Reflex will be executed immediately.
You can control the order in which CableReady and StimulusReflex operations execute in the client through strategic use (and non-use) of
- 1.CableReady operations that are
- 3.CableReady operations that haven't been
CableReady operations that have
broadcastcalled on them well be immediately delivered to the client, while any CableReady operations queued in a Page or Selector Morph Reflex action that aren't broadcast by the end of the action will be broadcast along with the StimulusReflex-specific
morphoperations. The StimulusReflex operations execute first, followed by any remaining CableReady operations.
One clever example use of advanced CableReady+StimulusReflex operation ordering is
CableReady#push_state. There are scenarios where you might want to update your page and then change the URL. If you attempt to change the URL of the page during the Reflex action, the StimulusReflex
morphupdates will be unsuccessful due to the URL changing. StimulusReflex won't execute if the page has changed since the beginning of the Reflex.
push_statewithout actually calling
broadcast, this ensures that the Reflex page updates can occur before
push_statechanges the URL.
It's important to plan your use of CableReady operations that manipulate the DOM, in terms of timing and eliminating side-effects.
CableReady operations that are broadcasted from a Reflex action will be processed by the client before the Reflex action finishes executing. This means that if you change the DOM in a Page Morph Reflex, it will appear as though your change didn't work when in reality, it was overwritten by the Reflex a few milliseconds later. For this reason, it's rare to see CableReady used in Page Morph Reflex actions. Instead, you should send the HTML that you want to see, the first time, so that there's no need to update anything. After all, you can always use client-side callbacks to embellish your UI after a Reflex completes.
The concern is different with a Selector Morph. As discussed above, it's fine to use CableReady operations alongside StimulusReflex
morphmethod calls, especially to take advantage of functions not supported directly by StimulusReflex, such as CableReady's
However, you must take responsibility for ensuring that your CableReady operations do not erase, move, or otherwise disturb the DOM above the element which invoked the Reflex action. While StimulusReflex will do everything it can to locate the Stimulus controller attached to the Reflex, if the controller can't be located - or no longer exists - then the life-cycle callbacks will not execute.
This is because StimulusReflex needs to be able to locate the Stimulus controller which initiated the Reflex, and it expects it to be in the same place in your DOM hierarchy that it was when the Reflex started.
If you're making extensive use of StimulusReflex
morphand CableReady operations, you might consider installing radiolabel. It's a powerful visual aid that allows you to see your CableReady operations happen.