<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: M. E. Patterson</title>
    <description>The latest articles on DEV Community by M. E. Patterson (@mepatterson).</description>
    <link>https://dev.to/mepatterson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F435661%2F9b54e416-0d48-43a0-a49c-75dfdc1e4560.png</url>
      <title>DEV Community: M. E. Patterson</title>
      <link>https://dev.to/mepatterson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mepatterson"/>
    <language>en</language>
    <item>
      <title>Me on The Changelog</title>
      <dc:creator>M. E. Patterson</dc:creator>
      <pubDate>Mon, 05 Apr 2021 22:12:20 +0000</pubDate>
      <link>https://dev.to/mepatterson/me-on-the-changelog-3a91</link>
      <guid>https://dev.to/mepatterson/me-on-the-changelog-3a91</guid>
      <description>&lt;p&gt;If you missed my A List Apart article (or just want to hear more), check out my great interview with Jerod on The Changelog podcast. &lt;a href="https://changelog.com/podcast/435"&gt;https://changelog.com/podcast/435&lt;/a&gt;&lt;/p&gt;

</description>
      <category>changelog</category>
      <category>podcast</category>
      <category>rails</category>
    </item>
    <item>
      <title>Using Tippy.js with StimulusReflex and CableReady</title>
      <dc:creator>M. E. Patterson</dc:creator>
      <pubDate>Fri, 28 Aug 2020 20:24:47 +0000</pubDate>
      <link>https://dev.to/mepatterson/using-tippy-js-with-stimulusreflex-and-cableready-3gno</link>
      <guid>https://dev.to/mepatterson/using-tippy-js-with-stimulusreflex-and-cableready-3gno</guid>
      <description>&lt;p&gt;So you've got a killer &lt;a href="https://docs.stimulusreflex.com"&gt;StimulusReflex&lt;/a&gt;-based Rails app going, and you're using &lt;a href="https://cableready.stimulusreflex.com"&gt;CableReady&lt;/a&gt; all over the place, and the DOM is morphing, and everything is going great! Now, you're ready to start adding in some tooltips here and there to polish up your user experience. Enter &lt;a href="https://atomiks.github.io/tippyjs/"&gt;Tippy.js&lt;/a&gt; for much success.&lt;/p&gt;

&lt;p&gt;At first, you just add an event handler listening to turbolinks reloads and have it initialize all the tippy elements on the page. And that works great...&lt;/p&gt;

&lt;p&gt;...until you use a Reflex to morph the DOM. Ack! Elements that were morphed that were supposed to have Tippy(s) now... don't.&lt;/p&gt;

&lt;p&gt;Of course, this makes sense. StimulusReflex, via CableReady, is morphing the DOM; it's not a Turbolinks load. So we'll need to change that.&lt;/p&gt;

&lt;p&gt;First, get rid of the turbolinks event handler. We're just going to do this with Stimulus and a &lt;code&gt;cable-ready:after-morph&lt;/code&gt; event handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tippy_controller.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tippy&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tippy.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cable-ready:after-morph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeTippys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeTippys&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyTippys&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;initializeTippys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyTippys&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;tippy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[data-tippy-content]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;destroyTippys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;tips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[data-tippy-content]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;tips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_tippy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_tippy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Cool. Now that that's out of the way, you just need to add &lt;code&gt;data-controller="tippy"&lt;/code&gt; to the right element(s) in your HTML. Personally, I just add it to the BODY tag so I can always make tooltips anywhere, any time.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;(let me know in the comments if there's an issue with this approach, or you have a better way, but it worked for me!)&lt;/p&gt;

</description>
      <category>rails</category>
      <category>javascript</category>
      <category>stimulusreflex</category>
      <category>cableready</category>
    </item>
    <item>
      <title>Getting Rails ApplicationController.renderer to render images and know about the Rack session</title>
      <dc:creator>M. E. Patterson</dc:creator>
      <pubDate>Mon, 17 Aug 2020 18:15:59 +0000</pubDate>
      <link>https://dev.to/mepatterson/getting-rails-applicationcontroller-renderer-to-render-images-and-know-about-the-rack-session-2205</link>
      <guid>https://dev.to/mepatterson/getting-rails-applicationcontroller-renderer-to-render-images-and-know-about-the-rack-session-2205</guid>
      <description>&lt;p&gt;This is going to be a really short one. It took me several hours to figure both of the following tricks out, so I figured I'd share for the next dev who gets stumped like I was. &lt;/p&gt;

&lt;p&gt;Let's say you're rendering a chunk of HTML somewhere other than in a view, using Rails &lt;code&gt;ApplicationController.renderer&lt;/code&gt; approach. As you might have figured out, this sets up a renderer with a &lt;strong&gt;default&lt;/strong&gt; request environment, which is probably fine for your average partial or whatever. &lt;/p&gt;

&lt;h3&gt;
  
  
  But I need images!
&lt;/h3&gt;

&lt;p&gt;Right, so, you've noticed that your &lt;code&gt;img&lt;/code&gt; tags aren't rendering properly because the default request environment sets up as "example.com" instead of localhost or whatever your actual deployed host might be. So we need to get in there and override some things in our fancy-pants custom renderer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;http_host: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host_with_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;https: &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"https://"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;partial: &lt;/span&gt;&lt;span class="s2"&gt;"widgets/something"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This ensures your renderer knows about your current &lt;em&gt;actual&lt;/em&gt; request environment's host, port, and protocol, which will enable the &lt;code&gt;img&lt;/code&gt; tags to be rendered correctly with proper URLs.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about the session stuff?
&lt;/h3&gt;

&lt;p&gt;Yeah, so in some weird circumstances, you might have a partial, or a &lt;a href="https://github.com/github/view_component"&gt;component&lt;/a&gt;, and you need it to render in some out-of-band way, maybe using web socket-driven &lt;a href="https://github.com/hopsoft/cable_ready"&gt;DOM mutations&lt;/a&gt;, say, and you need access to all the normal stuff from the Rack session. Here ya go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;http_host: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host_with_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;https: &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"https://"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s2"&gt;"rack.session"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;partial: &lt;/span&gt;&lt;span class="s2"&gt;"widgets/something"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;n.b. Depending on your circumstance, you &lt;em&gt;might&lt;/em&gt; actually have access to an instantiated legit controller; in this case, you might also get away with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;partial: &lt;/span&gt;&lt;span class="s2"&gt;"widgets/something"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...but if you don't have a controller instance, but you &lt;em&gt;do&lt;/em&gt; need images and session access, the above trick should help you out!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>rack</category>
      <category>components</category>
    </item>
    <item>
      <title>A New Era in Rails Development</title>
      <dc:creator>M. E. Patterson</dc:creator>
      <pubDate>Tue, 21 Jul 2020 17:31:45 +0000</pubDate>
      <link>https://dev.to/mepatterson/a-new-era-in-rails-development-20k1</link>
      <guid>https://dev.to/mepatterson/a-new-era-in-rails-development-20k1</guid>
      <description>&lt;p&gt;Is that headline click-bait? Yes. &lt;br&gt;
Do I believe it? Also yes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; &lt;br&gt;
Think Rails is old, slow and past its prime? Think SPAs are the only way forward? Think again. &lt;a href="https://docs.stimulusreflex.com/"&gt;StimulusReflex&lt;/a&gt; introduces a simple, blazingly fast new way to build incredible Rails apps. Go! Click it! I'll wait...&lt;/p&gt;

&lt;p&gt;First off, I'm not some big name in the Rails or Ruby community. I'm not a core contributor. I know some folks, but I'm the quiet guy in the back room. I don't sit up nights working on new frameworks or libraries to try and push the envelope forward for the industry as a whole. Part of me would love to be that developer, but I'm just not. &lt;/p&gt;

&lt;p&gt;I'm a practitioner. &lt;/p&gt;

&lt;p&gt;I've built &lt;a href="https://skillsengine.com"&gt;software that helps people enhance their careers&lt;/a&gt;; software that &lt;a href="https://gearboxsoftware.com"&gt;gets gamers deeper into their favorite game communities&lt;/a&gt;; worked on software that sells event tickets; software that presents network security dashboards to CTOs; software that configures SAN appliances; and software that trains Army battle captains. &lt;/p&gt;

&lt;p&gt;I'm not listing these bona fides to make myself look fancy, but to suggest that I make and manage teams that make &lt;em&gt;big, complicated apps&lt;/em&gt; that do stuff beyond your average blog site or Twitter clone. And I've built most of these things with Rails, Rails APIs + JavaScript SPAs, or with all of the above plus a host of connected systems, command-line tools, and machine-learning-based microservices.&lt;/p&gt;

&lt;p&gt;I like Rails. I love Ruby. I don't buy the notion that Ruby apps can't be fast, because I helped launch Ruby apps that handily serviced an unholy crush of gamers at the midnight release of a triple-A game title, and backend Rails APIs that powered everything from popular mobile apps to SPAs. But in the past few years, I've had to begrudgingly admit that Rails, out-of-the-box, wasn't so great at competing with the quick, responsive, reactive experiences powered by modern Javascript frameworks like React, Angular, Ember et al.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But this is about to change.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My current tabletop RPG group is a bunch of dads, spread across the US, who've been playing D&amp;amp;D virtually through Zoom for several years. But suddenly, with lockdowns and kids permanently at home, we found ourselves (paradoxically, it might seem) with even less time to play. I'd already been toying with the idea of building a web app to help streamline game sessions, but the pandemic sent me into overdrive. With the (very) limited free time I had left, between homeschooling my kids and my day job, I started looking in earnest for a tech stack to build the app with. I had three requirements: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The app needed to be really quick, smooth, and have a modern, reactive UX.&lt;/li&gt;
&lt;li&gt;I needed to be able to build it, quickly, by myself.&lt;/li&gt;
&lt;li&gt;I wanted to learn something new.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Could I build it with "classic" Rails? Sure. I'm real good at that... 15 years good at that, and I could cobble it together with spaghetti JS and get close to my goals. But I wanted something more ambitious, something more organized, and something where I could hone some skills. I looked at SPA frameworks like React, Angular, and Ember. They're amazing, and I have existing experience there through my day job. I figured I could beef up my existing SPA skills, and started down that path, but kept getting cold feet every time I looked at &lt;em&gt;two&lt;/em&gt; git repos that I would have to build simultaneously, and a JSON-based interface to bridge them... or maybe GraphQL, but now I'd be fighting performant queries on the backend, or... ugh. With a team of developers, sure, I could push all that complexity off onto &lt;em&gt;multiple people power&lt;/em&gt;, and it's a totally viable strategy. But Goal 2 was to see what I could build &lt;em&gt;with 1 person&lt;/em&gt;; something that could compete with the reactive apps being built by whole teams (like the one I manage). Was it even possible?&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://stimulusjs.org/"&gt;Stimulus&lt;/a&gt;, &lt;a href="https://docs.stimulusreflex.com/"&gt;StimulusReflex&lt;/a&gt;, &lt;a href="https://cableready.stimulusreflex.com/"&gt;CableReady&lt;/a&gt;, &lt;a href="https://github.com/joshleblanc/view_component_reflex"&gt;ViewComponentReflex&lt;/a&gt;, &lt;a href="https://dev.to/leastbad/introducing-optimism-realtime-remote-form-validation-for-rails-po6"&gt;Optimism&lt;/a&gt;, and their buddies. Enter surgical HTML-over-websockets. Enter hyper-responsive user interactions that &lt;em&gt;don't create state synchrony nightmares&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/FG0jgcFyN5k"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Within four days (and really, we're talking a couple hours each night after the kids go to bed), I had a prototype of &lt;a href="https://chaosmage.app"&gt;ChaosMage&lt;/a&gt; up and running that had the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NO full page reloads after the initial load&lt;/li&gt;
&lt;li&gt;Controller actions and reflexes that resolve as fast as any JSON API endpoint&lt;/li&gt;
&lt;li&gt;Real-time JS-driven bells and whistles on nearly every user-facing page that could benefit from them&lt;/li&gt;
&lt;li&gt;Far less JS for the browser to load, since there's no state management libraries on the client&lt;/li&gt;
&lt;li&gt;A clean, organized, component-based code architecture that works seamlessly with all the standard Rails stuff, and sidecars .rb, .js, and html templates together&lt;/li&gt;
&lt;li&gt;CSS transitions for every button, User and Character avatars (with a JS cropping tool!), pop-up modals, pop-over drawers, remote forms with real-time validation, you name it...&lt;/li&gt;
&lt;li&gt;A Three.js-based dice roller with physics and collisions, served and controlled by Rails and Stimulus controllers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A complete, Discord-like chat channel, complete with emojis, dice rolling commands, markdown support, parsing and re-rendering, and near-instantaneous broadcast of messages to everyone in the channel in under 50ms&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within a week, I had the app up on &lt;a href="https://www.hatchbox.io/"&gt;Hatchbox&lt;/a&gt; and alpha-tested with my gaming group on our next session. It worked flawlessly. Dice were rolled. Chats were... chatted? For the first hour, they thought I had found this new app somewhere online and didn't realize I had built it myself in just a few days.&lt;/p&gt;

&lt;p&gt;I suddenly re-experienced the feeling I had back in 2005, tinkering with one of the earliest releases of Rails; the feeling of leaving behind the PHP development where I'd spent most of my time setting up the architecture of my project. Instead, I was getting some new, delightful feature up-and-running every hour. &lt;/p&gt;

&lt;p&gt;For the past few years, I've been primarily building high-performance API endpoints to power fancy, reactive, gorgeous SPAs written fully in JS. I've been watching front-end teams fight race conditions with the back-end. I've been designing weird data architectures to make opinionated JS frameworks happy with the giant piles of JSON they're asking for. I've facepalmed at 50ms page loads, only to see an empty page full of spinners that, in total, take 3 seconds to all finally resolve. &lt;strong&gt;This wasn't what I was promised.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But with this new way of thinking about and building Rails apps, I suddenly found myself &lt;em&gt;single-handedly&lt;/em&gt; launching features again. My view templates just pull together smart, wired-up components. Reflexes let me keep the state the user is experiencing totally in-sync with the back-end reality with only a few lines of code. Pages in the app render with few spinners and everything already on-page, &lt;em&gt;often in under 100ms&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Developing an app &lt;em&gt;feels&lt;/em&gt; fun again.&lt;/p&gt;

&lt;p&gt;I didn't realize how much I'd missed that feeling in the past couple years.&lt;/p&gt;

&lt;p&gt;Now don't get me wrong. Developers can get this feeling from all sorts of tech stacks. React folks are feeling it. Angular and Ember folks are feeling it. Developers are sinking their teeth into Elixir and Phoenix, Vue and Alpine and everything else. So much amazing work is being done right now and there is an embarrassment of tools available to do incredible stuff. And, frankly, if you're not up-leveling your Javascript skills in &lt;em&gt;one way or another&lt;/em&gt;, I think you're falling behind. My experience is, of course, mine.&lt;/p&gt;

&lt;p&gt;But I truly believe that we shouldn't have to spin up &lt;em&gt;two&lt;/em&gt; code repos to make something non-trivial. (And for many companies, this means two teams or a team with bifurcated 'front-end' vs 'back-end' responsibilities.)&lt;/p&gt;

&lt;p&gt;We shouldn't need to spend days and multiple team meetings iterating on our data communications schema.&lt;/p&gt;

&lt;p&gt;We shouldn't be building one-size-fits-all API endpoints that sacrifice performance for front-end compatibility. &lt;/p&gt;

&lt;p&gt;We shouldn't be jamming megabytes of client-side code onto users' low-end laptops until they crash Chrome.&lt;/p&gt;

&lt;p&gt;Sub-second page loads with multiple seconds-worth of spinners isn't an enjoyable user experience.&lt;/p&gt;

&lt;p&gt;And are we really okay with sending &lt;strong&gt;more bytes of JSON than the actual HTML we're going to mutate on the front-end with it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm sure some folks reading this will say, "But, my dude, you're probably just building your API+SPA stacks wrong." And they might be right. Lots of great apps are built with SPAs, and with a dedicated team, we can build just about anything. I'm sure there's plenty of room for optimizing architectures and processes.&lt;/p&gt;

&lt;p&gt;But with StimulusReflex, CableReady, ViewComponents, and Optimism, &lt;strong&gt;we don't have to.&lt;/strong&gt; We're now looking at a completely new way of building reactive modern apps, while still using an established framework that has a huge community of awesome people and existing libraries and solutions for common challenges.&lt;/p&gt;

&lt;p&gt;And just think: if I can do all of that &lt;em&gt;by myself,&lt;/em&gt; imagine what a team of full-time devs could do!&lt;/p&gt;

&lt;p&gt;And in 2020, with the way things are going, we need tools that feel great and get us quick wins for non-trivial challenges, because we've got way too much to worry about otherwise. &lt;/p&gt;

&lt;p&gt;Don't believe me that 2020 could mark a new era of Rails development? That's okay. Do your thing and be happy! Build awesome stuff that makes people happy in these unhappy times, using whatever tech makes &lt;em&gt;you&lt;/em&gt; happy.&lt;/p&gt;

&lt;p&gt;But if, like me, you've been feeling like &lt;em&gt;maybe there's a simpler, quicker way&lt;/em&gt; to ambitious software, without sacrificing a modern UX... well, I'm urging you to take a look at what I think is a coming sea change:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stimulusjs.org/"&gt;Stimulus&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.stimulusreflex.com/"&gt;StimulusReflex&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cableready.stimulusreflex.com/"&gt;CableReady&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/github/view_component"&gt;ViewComponent&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/joshleblanc/view_component_reflex"&gt;ViewComponentReflex&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/leastbad/introducing-optimism-realtime-remote-form-validation-for-rails-po6"&gt;Optimism&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/julianrubisch/futurism"&gt;Futurism&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go check out this growing &lt;strong&gt;new ecosystem&lt;/strong&gt;. Definitely toy with the demos and expos. But also take it from me: these aren't just clever trick libraries made to show off some weird thing you can do. This is a new paradigm, folks. This is a new path forward, a third option way beyond 'classic' server-rendered apps and API+SPA verticals.&lt;/p&gt;

&lt;p&gt;I'm fully onboard, and I don't jump onto shiny new trains lightly. I intend to see where these new rails go.&lt;/p&gt;

&lt;p&gt;(Hey, and if you're playing D&amp;amp;D, 13th Age, or Starfinder, keep your eyes on &lt;a href="https://chaosmage.app"&gt;chaosmage.app&lt;/a&gt; ... I intend to open this thing up for everybody once it's polished up real nice!)&lt;/p&gt;

</description>
      <category>rails</category>
      <category>stimulus</category>
      <category>ruby</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
