ruby-on-railsactioncableruby-on-rails-7rails7

Ruby on Rails 7 Action Cable


I've upgraded from Rails 6 to 7 and now my action cable channels are not listening anymore. I'm sure it's a silly mistake but for the life of me I cannot track it down.

app/javascript/channels/consumer.js

import { createConsumer } from "@rails/actioncable"

export default createConsumer()

app/javascript/channels/settings_channel.js

import consumer from "./consumer"

consumer.subscriptions.create({ channel: "SettingsChannel" })

document.addEventListener('turbo:load', () => {
  //console.log(attendance_id);
  
  consumer.subscriptions.create({ channel: "SettingsChannel"}, {
    connected() {
      console.log("connected to settings channel ");
    },

    disconnected() {
      // Called when the subscription has been terminated by the server
    },

    received(data) {
      console.log("settings channel data:");
      console.log(data);

      if(data.tab){
        //clear other selected tabs first then highlight selected ones.

        const actions_tab = document.getElementById('actions-tab');
        if(actions_tab){
          actions_tab.classList.remove('settings-active-tab','settings-inactive-tab');
          if(data.tab == 'actions'){
            actions_tab.classList.add('settings-active-tab');
          }else{
            actions_tab.classList.add('settings-inactive-tab');
          }
        }
        const committees_tab = document.getElementById('committees-tab');
        if(committees_tab){
          committees_tab.classList.remove('settings-active-tab','settings-inactive-tab');
          if(data.tab == 'committees'){
            committees_tab.classList.add('settings-active-tab');
          }else{
            committees_tab.classList.add('settings-inactive-tab');
          }
        }
        const members_tab = document.getElementById('members-tab');
        if(members_tab){
          members_tab.classList.remove('settings-active-tab','settings-inactive-tab');
          if(data.tab == 'members'){
            members_tab.classList.add('settings-active-tab');
          }else{
            members_tab.classList.add('settings-inactive-tab');
          }
        }
        const motions_tab = document.getElementById('motions-tab');
        if(motions_tab){
          motions_tab.classList.remove('settings-active-tab','settings-inactive-tab');
          if(data.tab == 'motions'){
            motions_tab.classList.add('settings-active-tab');
          }else{
            motions_tab.classList.add('settings-inactive-tab');
          }
        }
        const session_tab = document.getElementById('session-tab');
        if(session_tab){
          session_tab.classList.remove('settings-active-tab','settings-inactive-tab');
          if(data.tab == 'session'){
            session_tab.classList.add('settings-active-tab');
          }else{
            session_tab.classList.add('settings-inactive-tab');
          }
        }
        const system_tab = document.getElementById('system-tab');
        if(system_tab){
          system_tab.classList.remove('settings-active-tab','settings-inactive-tab');
          if(data.tab == 'system'){
            system_tab.classList.add('settings-active-tab');
          }else{
            system_tab.classList.add('settings-inactive-tab');
          }
        }
      }

//end of inserted code for data received
    }
  });

})

app/javacript/application.js

import "@hotwired/turbo-rails"
//below is not supported yet
//import "@hotwired/stimulus-importmap-autoloader"
import "./controllers"
import "@rails/actioncable"   
import "@rails/activestorage" 
import "./channels"

import Rails from "@rails/ujs"
window.Rails = Rails;
if(Rails.fire(document, "rails:attachBindings")){
  Rails.start();
}

app/config/importmap.rb

# Pin npm packages by running ./bin/importmap

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
#pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
# Use libraries available via the asset pipeline (locally or via gems). # Rails 7.0 required
pin "@rails/actioncable", to: "actioncable.esm.js"      
pin "@rails/activestorage", to: "activestorage.esm.js" 

Thanks in advance for any advice! I had this working well with turbolinks in Rails 6 :-/


Solution

  • Solved it!

    My issue was within channels/index.js

    By default rails 7 ships with the following code in channels/index.js

    const channels = require.context('.', true, /_channel\.js$/)
    channels.keys().forEach(channels)
    

    this code is meant to automatically import all *_channel.js files. Problem is this is NOT supported in stimulus yet (for channels and controllers)...see this thread: https://github.com/hotwired/stimulus-rails/issues/73

    So my solution was to load them manually until the auto loading is supported.

    Here's the new code in channels/index.js:

    import "./settings_channel"
    import "./vote_channel"
    import "./member_vote_channel"
    import "./attendance_channel"