<?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: Andrea Rocca 👨‍🍳</title>
    <description>The latest articles on DEV Community by Andrea Rocca 👨‍🍳 (@ilrock__).</description>
    <link>https://dev.to/ilrock__</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%2F143020%2Fc3fe5a84-7a4d-48dd-a47e-ac4a4bf9299f.jpg</url>
      <title>DEV Community: Andrea Rocca 👨‍🍳</title>
      <link>https://dev.to/ilrock__</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ilrock__"/>
    <language>en</language>
    <item>
      <title>Reactive Map with Rails, Stimulus Reflex and Mapbox</title>
      <dc:creator>Andrea Rocca 👨‍🍳</dc:creator>
      <pubDate>Wed, 24 Jun 2020 10:54:15 +0000</pubDate>
      <link>https://dev.to/ilrock__/reactive-map-with-rails-stimulus-reflex-and-mapbox-1po4</link>
      <guid>https://dev.to/ilrock__/reactive-map-with-rails-stimulus-reflex-and-mapbox-1po4</guid>
      <description>&lt;p&gt;Hello folks.  &lt;/p&gt;

&lt;p&gt;In the last couple of weeks I've seen more and more content being posted about Rails (possibly because &lt;a href="https://hey.com"&gt;Hey&lt;/a&gt; officially launched) as well as Stimulus and Stimulus Reflex.  &lt;/p&gt;

&lt;p&gt;I've used Stimulus in the past and thought that it was a very good solution to wiring up the HTML with your javascript, however, that still didn't take care of the infamous &lt;strong&gt;reactivity&lt;/strong&gt; that frontend frameworks like Vue and React offer.  &lt;/p&gt;

&lt;p&gt;Stimulus reflex is supposed to help with that. The route that Stimulus reflex takes, however, is very different. It doesn't rely on you having to add any more JavaScript to your project as the reactivity is made possible thanks to some ruby files called reflexes.&lt;/p&gt;

&lt;p&gt;Let's see how it works. I chose again to use a very common "feature" often implemented by my students: a map that you can add markers onto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;Let's start by creating a new Rails project using Stimulus.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails new mapbox_reflex --webpack=stimulus&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we can add the Stimulus reflex gem&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bundle add stimulus_reflex&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And finally we can run the installer&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails stimulus_reflex:install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The installer will do a couple of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It will create a &lt;code&gt;app/reflexes&lt;/code&gt; directory and populate it with an &lt;code&gt;application_reflex.rb&lt;/code&gt; and &lt;code&gt;example_reflex.rb&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Update the javascript dependencies as well as the stimulus controller files to support Stimuls reflex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make things slightly easier on the eye let's also add bootstrap using a CDN (I know, not the best practice but this is about Stimulus reflex after all, no need to further complicate things). Let's go in our &lt;code&gt;application.html.erb&lt;/code&gt; and add the link tag&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;MapboxReflex&amp;lt;/title&amp;gt;
    &amp;lt;%= csrf_meta_tags %&amp;gt;
    &amp;lt;%= csp_meta_tag %&amp;gt;

    &amp;lt;%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %&amp;gt;
    &amp;lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"&amp;gt;
    &amp;lt;%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %&amp;gt;
  &amp;lt;/head&amp;gt;

  &amp;lt;body&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mapbox Setup
&lt;/h3&gt;

&lt;p&gt;Before moving forward, let's create the db&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails db:create&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To generate the sqlite3 db file and, before migrating the thing let's quickly scaffold a new table and migrate the database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails g scaffold Poi name latitude:float longitude:float&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails db:migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is going to create a new migration/model/controller/views for the Pois table (short for Points Of Interest).&lt;/p&gt;

&lt;p&gt;As you can see we added a latitude and longitude columns that we'll need to populate when creating a new POI. We can easily do that using the &lt;code&gt;geocoder&lt;/code&gt; gem.&lt;/p&gt;

&lt;p&gt;Let's add the gem to the gemfile &lt;code&gt;bundle add geocoder&lt;/code&gt; and wire it up with the Poi model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Poi &amp;lt; ApplicationRecord
  geocoded_by :name
  after_validation :geocode, if: :will_save_change_to_name?
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make sure that every time a certain POI gets an update to the name, we geocode it with the right latitude and logitude.&lt;/p&gt;

&lt;p&gt;Of course, we'll need to display this POI on a map and to do that, we'll use Mapbox. First of all let's install it &lt;code&gt;yarn add mapbox-gl&lt;/code&gt; then, you'll need to generate a new API token after creating a &lt;a href="https://account.mapbox.com/auth/signup/"&gt;new account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use this token, let's create a new &lt;code&gt;.env&lt;/code&gt; file and add this line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAPBOX_API_KEY=pk. ***********************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not really going to work unless we first add the dotenv gem to our Gemfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'dotenv-rails'
end
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and install the dependency &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's now add the map to the page. First of all, let's add some code to the &lt;code&gt;pois_controller.rb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PoisController &amp;lt; ApplicationController
  def index
    @pois = Poi.geocoded
    @markers = @pois.map do |poi|
      { lat: poi.latitude, lng: poi.longitude}
    end
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're simply getting the Pois along with their coordinates and we're creating a simple hash with their latitute and longitude.&lt;/p&gt;

&lt;p&gt;Next, let's edit the &lt;code&gt;views/pois/index.html.erb&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;div
    id="map"
    style="width: 100%; height: 600px;"
    data-controller="mapbox"
    data-markers="&amp;lt;%= @markers.to_json %&amp;gt;"
    data-mapbox-api-key="&amp;lt;%= ENV['MAPBOX_API_KEY'] %&amp;gt;"
  &amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, I also added a bunch of data properties that will be used by Stimulus. The first one &lt;code&gt;data-controller&lt;/code&gt; will create a new instance of the class defined in &lt;code&gt;mapbox_controller.js&lt;/code&gt;.  This file doesn't exist yet, let's create it&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch touch app/javascript/controllers/mapbox_controller.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And add this code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Controller } from 'stimulus'
import mapboxgl from 'mapbox-gl'
export default class extends Controller {
  connect() {
    this.map = null
    this.initMapbox()
  }

  initMapbox() {
    const mapElement = document.getElementById('map')
    const markers = JSON.parse(mapElement.dataset.markers)

    if (mapElement) {
      mapboxgl.accessToken = mapElement.dataset.mapboxApiKey
      this.map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v10',
        zoom: 5,
        center: ['12.4964', '41.9028']
      })

      markers.forEach((marker) =&amp;gt; {
        this.addMarker(marker)
      })
    }
  }

  addMarker(marker) {
    new mapboxgl.Marker().setLngLat([marker.lng, marker.lat]).addTo(this.map)
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what is happening in here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The connect method is called whenever the a new instance of the class is created (this is what the &lt;code&gt;data-controller&lt;/code&gt; is for). In this method we set the map to null and we call another method called &lt;code&gt;initMapbox&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In this method we grab the markers from the &lt;code&gt;data-markers&lt;/code&gt; property (that is mapped to the instance variable &lt;code&gt;@markers&lt;/code&gt;) and create a new map using &lt;code&gt;mapbox-gl&lt;/code&gt;. Then, we add each one of those markers to the map using the &lt;code&gt;addMarker&lt;/code&gt; method&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's set the root of the app to the pois index page, start the rails server and test this out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails.application.routes.draw do
  root 'pois#index'
  resources :pois
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sdm0V5NH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ghost.meetandrearocca.com/content/images/2020/06/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sdm0V5NH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ghost.meetandrearocca.com/content/images/2020/06/image.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what you should be greeted with. Beautiful Italy.&lt;/p&gt;

&lt;p&gt;As you can see, the style is a bit off. Simply importing the mabox scss file inside our &lt;code&gt;app/assets/stylesheets/application.scss&lt;/code&gt; will make things look a lot better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @import 'mapbox-gl/dist/mapbox-gl';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There may be a chance that your map is gray and you have js errors in your console. If that is the case add this line to your &lt;code&gt;environment.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment.loaders.delete('nodeModules')

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just before exporting the module.&lt;/p&gt;

&lt;p&gt;All good for now. There are still no markers, though. Let's take care of that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding markers with Stimulus Reflex
&lt;/h3&gt;

&lt;p&gt;Let's add some more code to the pois index view&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div
  id="map"
  style="width: 100%; height: 600px;"
  data-controller="mapbox"
  data-markers="&amp;lt;%= @markers.to_json %&amp;gt;"
  data-mapbox-api-key="&amp;lt;%= ENV['MAPBOX_API_KEY'] %&amp;gt;"
&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;form data-controller="pois" class="mt-5 container"&amp;gt;
  &amp;lt;div class="form-group"&amp;gt;
    &amp;lt;label for="poi_name"&amp;gt;POI Name&amp;lt;/label&amp;gt;
    &amp;lt;input
      class="form-control"
      type="text"
      data-target="pois.address"
      name="poi_name"
      id="poi_name"
    &amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;button
    data-action="click-&amp;gt;pois#add"
    type="submit"
    class="btn btn-primary"
  &amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is simply going to add a new form to the view. As you can see, we're also instantiating another stimulus controller called &lt;code&gt;pois_controller&lt;/code&gt; and we're wiring up the button click event to a method inside that controller called &lt;code&gt;add&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This controller doesn't exist yet. Let's create it&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch app/javascript/controllers/pois_controller.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And add this stuff in there&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import ApplicationController from './application_controller'
import Rails from '@rails/ujs'

export default class extends ApplicationController {
  static targets = ['address']

  add(e) {
    Rails.stopEverything(e)

    this.stimulate('PoisReflex#add', this.addressTarget.value)
  }

  afterAdd() {
    this.addressTarget.value = ''
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what is happening in here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We're declaring a target called address. This is directly connected to the input tag where we used the data property &lt;code&gt;data-target&lt;/code&gt;. This will make it easier for us to access that element using javascript&lt;/li&gt;
&lt;li&gt;In the add method we're first stopping any Rails default behavior and then, we're calling the &lt;code&gt;stimulate&lt;/code&gt; method that was made available by Stimulus reflex (inside the &lt;code&gt;application_controller.js&lt;/code&gt; connect method). The stimulate method will now call the &lt;code&gt;PoisReflex&lt;/code&gt; add method passing through the input value of the address text field&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We haven't created yet the &lt;code&gt;PoisReflex.rb&lt;/code&gt; file. We can do so by using a rails generator &lt;code&gt;rails g stimulus_reflex Pois&lt;/code&gt;. This will create the &lt;code&gt;PoisReflex.rb&lt;/code&gt; file inside &lt;code&gt;app/reflexes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this file we now need to define a method &lt;code&gt;add&lt;/code&gt; that gets called by the stimulus controller&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PoisReflex &amp;lt; ApplicationReflex
  def add(name)
    Poi.create(name: name)
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this method is pretty simple. We simply grab the POI name and create a new POI with it. And this is it. Stimulus Reflex is now connected.&lt;/p&gt;

&lt;p&gt;Lets test restart our server and test this out. Go to the web page and type a POI, for instance &lt;code&gt;Colosseum&lt;/code&gt; and hit the submit button.&lt;/p&gt;

&lt;p&gt;You will see that the map suddenly disappears&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mjhglOxM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ghost.meetandrearocca.com/content/images/2020/06/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mjhglOxM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ghost.meetandrearocca.com/content/images/2020/06/image-1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because behind the scenes, Stimulus Reflex refreshes the bits of the page that are impacted by whatever happened in the reflex. In this case, in the reflex we created a new POI, which means that inside the index method of the &lt;code&gt;pois_controller.rb&lt;/code&gt; a new POI was added to the &lt;code&gt;@markers&lt;/code&gt; instance variables that the map depends on and thus the whole map element got re-rendered.&lt;/p&gt;

&lt;p&gt;This means that now all we need to do is initialize the map back every time a new reflex has completed. Luckily, this is pretty easy to do thanks to the Stimulus Reflex hooks. Let's go in &lt;code&gt;application_controller.js&lt;/code&gt; and add the &lt;code&gt;afterReflex&lt;/code&gt; hook to reinitialize mapbox.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Controller } from 'stimulus'
import StimulusReflex from 'stimulus_reflex'
import MapboxController from './mapbox_controller'

export default class extends Controller {
  connect() {
    StimulusReflex.register(this)
  }

  afterReflex() {
    const map = new MapboxController()

    map.initMapbox()
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see here we're importing &lt;code&gt;MapboxController&lt;/code&gt; and in the &lt;code&gt;afterReflex&lt;/code&gt; hook we are initializing mapbox again using an instance of the controller class.&lt;/p&gt;

&lt;p&gt;Now if we test things out again we'll see something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kH41M9_k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://ghost.meetandrearocca.com/content/images/2020/06/x9Dwdsrp6e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kH41M9_k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://ghost.meetandrearocca.com/content/images/2020/06/x9Dwdsrp6e.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty awesome if you ask me. With just a couple of lines of code Stimulus Reflex allowed us to create a fully reactive map.&lt;/p&gt;

&lt;p&gt;I've just started to play around with it so I'm sure things can be also further improved. If you want to get access to the code, you can find it &lt;a href="https://github.com/ilrock/mapbox_reflex"&gt;here&lt;/a&gt;, if you want to get it touch, you can tweet me &lt;a href="https://twitter.com/ilrock__"&gt;@ilrock__&lt;/a&gt; or email me @ andrearocca [at] hey [dot] com.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update
&lt;/h3&gt;

&lt;p&gt;The awesome StimulusReflex community came to the rescue after posting this and shared with me an improvement that I could have worked on. At the moment, every time a new POI is added, the whole map gets re-initialized. It works, but that is not ideal. To tackle this issue, I've changed &lt;code&gt;pois/index.html.erb&lt;/code&gt; to this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div
  data-controller="pois"
&amp;gt;
  &amp;lt;div
    style="width: 100%; height: 600px;"
    data-controller="mapbox"
    data-target="mapbox.wrapper"
    data-markers="&amp;lt;%= @pois.to_json %&amp;gt;"
    data-mapbox-api-key="&amp;lt;%= ENV['MAPBOX_API_KEY'] %&amp;gt;"
  &amp;gt;
    &amp;lt;div
      data-target="mapbox.map"
      data-reflex-permanent
      class="w-100 h-100"
    &amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;form
    data-target="pois.form"
    class="mt-5 container"
  &amp;gt;
    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="poi_name"&amp;gt;POI Name&amp;lt;/label&amp;gt;
      &amp;lt;input
        class="form-control"
        type="text"
        data-target="pois.address"
        name="poi_name"
        id="poi_name"
      &amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;button
      data-action="click-&amp;gt;pois#add"
      type="submit"
      class="btn btn-primary"
    &amp;gt;Submit&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main changes here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I nested the div that holds the map inside a wrapper. The wrapper has access to all the needed data (markers and api key)&lt;/li&gt;
&lt;li&gt;I marked the nested div with the data attribute data-reflex-permanent. This is a nifty StimulusReflex utility that will skip this div when reloading the interface (do you remember the blank div we were getting before re-initializing the map?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I then made some changes to the &lt;code&gt;mapbox_controller.js&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Controller } from 'stimulus'
import mapboxgl from 'mapbox-gl'

let currentInstance = null

export default class extends Controller {
  static targets = ['map', 'wrapper']

  connect() {
    this.map = null
    this.markers = null
    this.initMapbox()
  }

  initMapbox() {
    this.markers = JSON.parse(this.wrapperTarget.dataset.markers)

    mapboxgl.accessToken = this.wrapperTarget.dataset.mapboxApiKey

    this.map = new mapboxgl.Map({
      container: this.mapTarget,
      style: 'mapbox://styles/mapbox/streets-v10',
      zoom: 5,
      center: ['12.4964', '41.9028']
    })

    currentInstance = this

    this.markers.forEach((marker) =&amp;gt; {
      this.addMarker(marker)
    })
  }

  showNewMarkers() {
    const allMarkers = JSON.parse(this.wrapperTarget.dataset.markers)

    const newMarkers = allMarkers
      .filter((marker1) =&amp;gt; !this.markers.some((marker2) =&amp;gt; marker1.name == marker2.name))

    this.showNewMarkers()
  }

  addMarker(marker) {
    new mapboxgl.Marker().setLngLat([marker.longitude, marker.latitude]).addTo(this.map)
  }
}

export {
  currentInstance
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The changes here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I added a variable currentInstance that is assigned to &lt;code&gt;this&lt;/code&gt; when Stimulus instantiate an object with this class. This is then exported as it will be used at a later stage&lt;/li&gt;
&lt;li&gt;I added a new method &lt;code&gt;showNewMarkers&lt;/code&gt; that gets the difference between the markers that had already been added to the map (this.markers) and the ones coming from the data property of the now-reloaded wrapper (because it was reloaded it will also include the newly added marker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last but not least, I moved the afterReflex code to &lt;code&gt;pois_controller.js&lt;/code&gt; that now looks like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import ApplicationController from './application_controller'
import Rails from '@rails/ujs'
import { currentInstance } from './mapbox_controller'

export default class extends ApplicationController {
  static targets = ['address', 'form']

  add(e) {
    Rails.stopEverything(e)
    this.stimulate('PoisReflex#add', this.addressTarget.value)
  }

  afterAdd() {
    this.addressTarget.value = ''
  }

  afterReflex() {
    currentInstance.showNewMarkers()
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here now we're simply importing the &lt;code&gt;currentInstance&lt;/code&gt; that we exported earlier and calling the &lt;code&gt;showNewMarkers&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;These small changes now yield this result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6b6AlRS2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4knzgw9il5mxaptq30vr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6b6AlRS2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4knzgw9il5mxaptq30vr.gif" alt="final result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know if the changes do make sense! Thanks again a lot to &lt;a class="mentioned-user" href="https://dev.to/leastbad"&gt;@leastbad&lt;/a&gt;
 for the help.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>stimulus</category>
      <category>stimulusreflex</category>
    </item>
    <item>
      <title>A simple guide to ActionCable</title>
      <dc:creator>Andrea Rocca 👨‍🍳</dc:creator>
      <pubDate>Mon, 09 Mar 2020 23:21:04 +0000</pubDate>
      <link>https://dev.to/ilrock__/a-simple-guide-to-actioncable-1fm5</link>
      <guid>https://dev.to/ilrock__/a-simple-guide-to-actioncable-1fm5</guid>
      <description>&lt;p&gt;Hello folks. First blog post here on dev.to. For whom doesn't know me already (likely most of you), my name is Andrea and I am a freelance full-stack developer. On top of that, I often teach Ruby, Rails and Javascript at a coding bootcamp called LeWagon.&lt;/p&gt;

&lt;p&gt;It's been already two bootcamps in a row that some students had a really tough time integrating ActionCable in their app, mostly because the official Rails docs are pretty vague and there are a lot of contradicting blog posts on the internet. Well, fear no more. With this guide I'll try to make it as easy and smooth as possible. Enjoy the read.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick app introduction
&lt;/h3&gt;

&lt;p&gt;Much like my students, we'll create a (very) bare-bones Uber Chat application where we're going to have an Order that will connect a User and a Driver. These two, should then be able to exchange messages on the Order show page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rails app setup
&lt;/h3&gt;

&lt;p&gt;Let's start by creating a new Rails project by running &lt;code&gt;rails new uber_chat&lt;/code&gt; in your terminal&lt;/p&gt;

&lt;p&gt;This will create a &lt;code&gt;uber_chat&lt;/code&gt; directory with a shiny new Rails 6 project.&lt;/p&gt;

&lt;p&gt;Let's now add user authentication using good ol' &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This line goes into our Gemfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'devise'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's now run &lt;code&gt;bundle install&lt;/code&gt; to make the devise Gem available in our project. Now, we need to let devise add some boilerplate code in our project by running &lt;code&gt;rails g devise:install&lt;/code&gt; first and &lt;code&gt;rails g devise User&lt;/code&gt; after.&lt;/p&gt;

&lt;p&gt;This last command will add the devise routes to our routes file and will generate a migration and model files for our users. Let's now add the Users table to our db by running &lt;code&gt;rails db:migrate&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding drivers and orders
&lt;/h3&gt;

&lt;p&gt;Let's now add two new models to our DB&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails g model driver user:references&lt;/code&gt; &lt;br&gt;
&lt;code&gt;rails g model order user:references driver:references&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create the Driver and Order models together with the respective migrations. Let's now migrate the db with &lt;code&gt;rails db:migrate&lt;/code&gt; and add the following to the User model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# User.rb&lt;/span&gt;
&lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:driver&lt;/span&gt;
&lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:orders&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sweet! Now our users can have many orders and some of them, can also be drivers. Let's add some seed data so that we can actually use the application. Paste this in your seed file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# seeds.rb&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Resetting the db..."&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy_all&lt;/span&gt;
&lt;span class="no"&gt;Driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy_all&lt;/span&gt;
&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy_all&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Creating a user..."&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s1"&gt;'user@test.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password_confirmation: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Creating a driver"&lt;/span&gt;
&lt;span class="n"&gt;driver_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s1"&gt;'driver@test.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password_confirmation: &lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;driver_user&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Creating an order..."&lt;/span&gt;
&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt; &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;driver: &lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And now run &lt;code&gt;rails db:seed&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the messages and the views
&lt;/h3&gt;

&lt;p&gt;Let's add now a new model (and table) to the app to actually store the messages&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails g model message content:string user:references order:references&lt;/code&gt;&lt;br&gt;
&lt;code&gt;rails db:migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and let's add the relationship also on the User and Order models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# User.rb&lt;/span&gt;
&lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:messages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Order.rb&lt;/span&gt;
&lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:messages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Disclaimer #1 - here we could have gone deeper and we could have set up a more appropriate relationship to store the message author, however, because that is not the core part of this article I want to make it easier and quicker&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we will be able to create messages written by Users scoped to a certain order. Good stuff.&lt;/p&gt;

&lt;p&gt;Let's now add the Order index route that we'll use as our root path and the Order show route that will actually be responsible of showing the messages.&lt;/p&gt;

&lt;p&gt;In the routes file, let's add this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# routes.rb&lt;/span&gt;
&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s2"&gt;"orders#index"&lt;/span&gt;
&lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="sx"&gt;%i[index show]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now generate the Order controller and views using &lt;code&gt;rails g controller orders show index&lt;/code&gt; and let's make the controller look like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate_user!&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;orders&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nothing extraordinary here. We first make sure that the two pages are authentication protected (otherwise &lt;code&gt;current_user.orders&lt;/code&gt; would give us an error) and then we grab all the orders belonging to a user in the index and the order matching the :id parameter in the show.&lt;/p&gt;

&lt;p&gt;Now let's get the views done&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="c"&gt;&amp;lt;!-- orders/index.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt; Yo! These are your orders &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;orders.each&lt;/span&gt; &lt;span class="na"&gt;do&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;link_to&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;Order&lt;/span&gt; &lt;span class="na"&gt;#&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;order.id&lt;/span&gt;&lt;span class="err"&gt;}",&lt;/span&gt; &lt;span class="na"&gt;order_path&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="na"&gt;end&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- orders/show.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt; Order #&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;order.id&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt; Messages &lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"messages-box"&lt;/span&gt;
  &lt;span class="na"&gt;data-order-id=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= @order.id %&amp;gt;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"new-message-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Hola!"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"new-message-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The index file is pretty simple. We're just displaying all the orders belonging to a user.&lt;/p&gt;

&lt;p&gt;The show file is slightly more interesting. Here we are storing the order id as data attribute of the &lt;code&gt;.messages-box&lt;/code&gt; div. This will come in handy in a little bit. We're also adding the form that we'll later user in order to create new messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the API endpoint and Javascript calls
&lt;/h3&gt;

&lt;p&gt;In order to fetch the messages after page load and post a new message once a user has typed it, I like to add a /api namespace to my app in order to keep things nice and tidy.&lt;/p&gt;

&lt;p&gt;Let's add this stuff to the routes file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# routes.rb&lt;/span&gt;
&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;defaults: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;format: :json&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:v1&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:orders&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="sx"&gt;%i[index create]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The code above will now make it very easy to GET and POST to /api/v1/orders/:order_id/messages.&lt;/p&gt;

&lt;p&gt;Let's now create the appropriate folders and controller with the command &lt;code&gt;mkdir -p app/controllers/api/v1 &amp;amp;&amp;amp; touch app/controllers/api/v1/messages_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And add this code to the newly created MessagesController&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# messages_controller.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Api&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;V1&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
      &lt;span class="n"&gt;skip_before_action&lt;/span&gt; &lt;span class="ss"&gt;:verify_authenticity_token&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;

        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="n"&gt;message_params&lt;/span&gt;

        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;

        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="kp"&gt;private&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;message_params&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;    
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Disclaimer #2 - This is not an API post hence you shouldn't use this as a guide to create a robust API. In this case, for example, I'm not securing the endpoints for simplicity sake.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that the endpoints are ready, we can add our JavaScript code to load the messages on page load and to create new messages.&lt;/p&gt;

&lt;p&gt;Lets run &lt;code&gt;mkdir app/javascript/plugins -p &amp;amp;&amp;amp; touch app/javascript/plugins/messagesPlugin.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this file, let's now add this stuff&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;//messagesPlugin.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/v1/orders/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/messages`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;messages&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;message&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createMessage&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.new-message-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.new-message-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;

    &lt;span class="nx"&gt;form&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="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/v1/orders/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/messages`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; by &amp;lt;strong&amp;gt; User #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;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;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetchMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ok, there's a little more stuff to talk about here. The first &lt;code&gt;fetchMessages&lt;/code&gt; function is simply needed to make a GET request to our API in order to show all the messages on page load.&lt;/p&gt;

&lt;p&gt;Then, the &lt;code&gt;createMessage&lt;/code&gt; function is needed in order to POST a new message to our API.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;AddMessageToDom&lt;/code&gt; function is simply needed to show the messages on the page.&lt;/p&gt;

&lt;p&gt;Now, because we're exporting &lt;code&gt;fetchMessages&lt;/code&gt; and &lt;code&gt;createMessage&lt;/code&gt;, we also need to import them in our entry file &lt;code&gt;packs/application.js&lt;/code&gt;. Let's paste this code in there&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;// application.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;fetchMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createMessage&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="s1"&gt;../plugins/messagesPlugin&lt;/span&gt;&lt;span class="dl"&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;turbolinks:load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fetchMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;createMessage&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;Awesome! Now we're able to create messages directly from the application and the new messages will be displayed immediately to the page. Go have a look for yourself.&lt;/p&gt;

&lt;p&gt;Start the server using &lt;code&gt;rails s&lt;/code&gt;, then login using the credentials used to create the user in the seed file (&lt;a href="mailto:user@test.com"&gt;user@test.com&lt;/a&gt; and password) and then go to the Order #1 page and try to create a message.&lt;/p&gt;

&lt;p&gt;Just because we can see the message, that doesn't mean that the other person (the driver, for instance) will be able to do so. This is because we need to establish a communication channel between our backend and our frontend using &lt;strong&gt;ActionCable&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding ActionCable
&lt;/h3&gt;

&lt;p&gt;The first thing we want to do when dealing with ActionCable is generating a new channel. This can be done using the command &lt;code&gt;rails g channel chat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will generate a bunch of files for both the Ruby and the Javascript parts. Let's start adding some code to make it work.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;chat_channel.rb&lt;/code&gt; let's add this code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatChannel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationCable&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Channel&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subscribed&lt;/span&gt;
    &lt;span class="n"&gt;stream_from&lt;/span&gt; &lt;span class="s2"&gt;"order_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:order_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;unsubscribed&lt;/span&gt;
    &lt;span class="c1"&gt;# Any cleanup needed when channel is unsubscribed&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, thanks to the interpolation of the order_id we'll "stream" a different "chat room" for each different order.&lt;/p&gt;

&lt;p&gt;in &lt;code&gt;chat_channel.js&lt;/code&gt; let's add this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;consumer&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;./consumer&lt;/span&gt;&lt;span class="dl"&gt;"&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;addMessageToDom&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="s1"&gt;../plugins/messagesPlugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initChatChannel&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;

    &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ChatChannel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
      &lt;span class="nx"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connected...&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;received&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Receiving stuff...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initChatChannel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, we're using &lt;code&gt;consumer.subscriptions.create&lt;/code&gt; in order to create a new client that will actively listen for new messagess added to the "chat room".&lt;/p&gt;

&lt;p&gt;You can see that the first argument of the create method is an object that will be used to establish the connection to a specific channel (ChatChannel in this case). It's also import to pass the &lt;code&gt;order_id&lt;/code&gt; parameter in order to establish the connection to the right chat room as well (remember the &lt;code&gt;params[:order_id]&lt;/code&gt; used in chat_channel.rb?).&lt;/p&gt;

&lt;p&gt;The second argument, instead, is again an object that contains two methods. The &lt;code&gt;connected&lt;/code&gt; method will simply run whenever the client gets connected to the ActionCable server. The &lt;code&gt;received&lt;/code&gt; method, instead, is what makes the whole magic work. This method is automatically triggered whenever a new message is broadcasted on the channel that we connected our client to.&lt;/p&gt;

&lt;p&gt;In this case, we want to grab that message and pass it as an argument to the &lt;code&gt;addMessageToDom&lt;/code&gt; method that we're importing from the plugin we created earlier so that it can get displayed to the DOM.&lt;/p&gt;

&lt;p&gt;Finally, we need to tell the server to broadcast a message every time a new message is created on the database. To do so, we can edit our Message model to look like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:order&lt;/span&gt;

  &lt;span class="n"&gt;after_create&lt;/span&gt; &lt;span class="ss"&gt;:broadcast_through_action_cable&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;broadcast_through_action_cable&lt;/span&gt;
    &lt;span class="no"&gt;ActionCable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"order_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;broadcast_through_action_cable&lt;/code&gt; will simply broadcast the message to the right room according to the order id the message belongs to.&lt;/p&gt;

&lt;p&gt;Let's now get rid of some (now) useless code. Go to the &lt;code&gt;messagesPlugins.js&lt;/code&gt; and replace whatever you got in there with this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/v1/orders/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/messages`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;messages&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;message&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createMessage&lt;/span&gt; &lt;span class="o"&gt;=&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.new-message-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.new-message-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;

    &lt;span class="nx"&gt;form&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="s1"&gt;submit&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;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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/v1/orders/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/messages`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messagesBox&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.messages-box&lt;/span&gt;&lt;span class="dl"&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;messagesBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messagesBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;beforeend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; by &amp;lt;strong&amp;gt; User #&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;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;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetchMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addMessageToDom&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we simply removed the call to the &lt;code&gt;addMessageToDom&lt;/code&gt; method from the &lt;code&gt;createMessage&lt;/code&gt; method because now we're outsourcing the creation of new messages to the ActionCable receiver.&lt;/p&gt;

&lt;p&gt;This is the result of all of this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YxgBgxGM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r3nb5rpai1bx9sim6j0m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YxgBgxGM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r3nb5rpai1bx9sim6j0m.gif" alt="Action cable in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you guys found this helpful. (Contructive) Criticism is always very welcome. If you got any question, feel free to comment down below or tweet me &lt;a href="https://twitter.com/ilrock__"&gt;@ilrock__&lt;/a&gt;. To check out the full source-code this is the &lt;a href="https://github.com/ilrock/uber_chat"&gt;GitHub link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>actioncable</category>
      <category>webpacker</category>
    </item>
  </channel>
</rss>
