DEV Community

Cover image for Live previews with Rails and StimulusReflex
leastbad
leastbad

Posted on • Updated on

Live previews with Rails and StimulusReflex

This morning I read Live previews with Rails and Stimulus 2, a post which compares the experience of implementing a text preview feature using server-rendered code. The author choose to use a "pure Ajax" approach with Stimulus, as well as what the same project would look like using Turbo Frames.

This post will present a 3rd option: StimulusReflex. The full source for this example is available on Github. Don't forget to change to the previews branch!


First, we'll need a template. I'm just going to use a vanilla tag helper:

<%= text_area_tag :body,
                  nil,
                  data: { reflex: "input->Composer#preview" } %>

<div id="preview"></div>
Enter fullscreen mode Exit fullscreen mode

The only thing required to make this feature work is a Reflex declared on the textarea element. input events captured will initiate a preview action on the Composer Reflex class. I also assigned an id attribute to the strong element so that we have a destination for the preview content.

class ComposerReflex < ApplicationReflex
  def preview
    morph "#preview", element.value
  end
end
Enter fullscreen mode Exit fullscreen mode

The preview action takes the value of the element which triggered the Reflex, and updates the #preview element in the browser. Behind the scenes, this is done using one of CableReady's 33 operations, inner_html.

That's it... there are no further steps. You don't need any extra templates, routes or Stimulus controllers.

If you open the Console Inspector, you'll see that each Reflex takes about 5ms, round-trip.


StimulusReflex and CableReady offer a simple but powerful RPC model for building reactive applications. The functionality of this stack eclipses Turbo in every meaningful dimension:

  • CR has ~7x as many verbs/operations as Turbo Streams (just CRUD)
  • CR supports adding custom operations
  • CR is incredibly flexible in terms of who or what you send updates to
  • CR operations can be chained and target multiple elements
  • CR can broadcast from anywhere in your app: jobs, reflexes, controllers, rake tasks, channels
  • CR can provide visual feedback when elements are updated
  • SR provides a transaction wrapper around each request
  • SR has a full life-cycle of events and callbacks on the server and client
  • SR Reflex updates use DOM diffing, not innerHTML, so Stimulus controller state is preserved
  • SR Reflexes can be initiated by JS or declared in markup
  • SR offers a highly performant RPC mechanism with Nothing Morphs
  • SR benefits from tight coupling with Stimulus
  • SR has really powerful server and client debug tooling
  • SR has exceptionally thorough documentation
  • SR has incredible free support
  • SR has a 2000+ person Discord community that is incredibly supportive

I hope that you'll consider updating your post with a third option, Josef!

Top comments (8)

Collapse
 
strzibny profile image
Josef Strzibny

Interesting!

Am I right in assuming that in the following snipped:

class ComposerReflex < ApplicationReflex
  def preview
    morph "#preview", element.value
  end
end
Enter fullscreen mode Exit fullscreen mode

We can now wrap "element.value" with any kind of Ruby method like a call to process Markdown?

Collapse
 
leastbad profile image
leastbad

Anything that ultimately ends up emitting a String, sir!

Collapse
 
drews256 profile image
Andrew Stuntz

While I agree that SR and CR are much more powerful than Turbo. I think comparing them is like comparing Apples and Oranges. It bugs me that so many folks are trying to compare the two when CR and SR are just different solutions in this same problem space. I don't think people should be trying to pick between SR and Turbo, they should be evaluating how they want to build an application and what they want to support and choosing the appropriate tool. They don't need to be competitors.

Collapse
 
leastbad profile image
leastbad

I think (?) we agree in spirit. We see Turbo Drive as the successor to UJS and, like UJS, we go out of our way to recommend that developers at least consider whether their needs can be addressed by those built-in tools.

The problem is the DHH himself positions Turbo as a superior alternative to SR, so we're stuck tackling FUD scenarios on a 1:1 basis where people are attempting to use the built-in tool to solve extremely complex UI scenarios for which SR/CR is designed for - and they are doing it because someone they trust made it.

If Turbo Drive had been released by an unknown developer, people would not be setting aside vastly simpler and more powerful tools to use it. Adding routes and keeping track of dozens or hundreds of "frames" is not, with any objective distance, a positive.

Collapse
 
drews256 profile image
Andrew Stuntz

Turbo Drive as the successor to UJS and, like UJS, we go out of our way to recommend that developers at least consider whether their needs can be addressed by those built-in tools.

Turbo is not even really "baked" in yet. My efforts to use Turbo in a few Rails apps I work on have gone really poorly. I'm super unimpressed. As a "add-on" for applications already in development Turbo (imo) sucks. It's impossible to make things "work" without rewriting a bunch of work that already exists.

Either way, I hear you. I wish DHH would be more on board with "other" solutions that are not his own. I hear him when he doesn't really wanna change the way "the internet works" with websockets doing funky things and dom diffing etc. But, SR/CR is powerful in so many different ways than Turbo.

Thread Thread
 
leastbad profile image
leastbad

Don't doubt for a moment: Hotwire and to a lesser extent Kredis are the marquee features of Rails 7. I don't know if you've noticed like we have but he responds to critiques with "still in beta" and when people ask if it's going to have major updates before Rails 7, he says "beta is just a word".

All I know is that if we don't stand up for and tell people about this thing we love (and have invested, cumulatively, thousands of hours into, for free) then nobody is going to do it for us - even if DHH didn't have a bad case of Not Invented Here syndrome.

Thanks for the thought provoking convo! I hope you can forgive a certain degree of parental pride in what we've created.

Thread Thread
 
drews256 profile image
Andrew Stuntz

Yeah, I know. I'm trying to be excited about it haha. I think it's fine. I really like Stimulus and I'm very excited to see the mobile "hotness" that is supposedly going to come out of Turbo. But I just know it's gonna pigeon hole me into writing and app in the same way that DHH would write it. While I don't think that is a bad thing, I don't think it's a good thing either.

I don't think you have enough parental pride! I'm using and generally loving every minute of working on an app with SR around. It's quite nice.

Thread Thread
 
leastbad profile image
leastbad

Flattery will get you everywhere!

We were saying yesterday that the biggest gift that Hotwire gives us is the assumption that Stimulus will be available by default. I don't think this gets nearly as much attention as it deserves - because it's freaking awesome.