A Vue plugin that makes integrating Rails Action Cable dead-easy.
ActionCableVue is an easy-to-use Action Cable integration for VueJS.
npm install actioncable-vue --save
// Vue 2.x import Vue from 'vue'; import ActionCableVue from 'actioncable-vue'; import App from './App.vue';Vue.use(ActionCableVue, { debug: true, debugLevel: 'error', connectionUrl: 'ws://localhost:5000/api/cable', // or function which returns a string with your JWT appended to your server URL as a query parameter connectImmediately: true, });
new Vue({ router, store, render: h => h(App) }).$mount('#app');
// Vue 3.x import { createApp } from 'vue'; import App from './App.vue'; import ActionCableVue from 'actioncable-vue';const actionCableVueOptions = { debug: true, debugLevel: 'error', connectionUrl: 'ws://localhost:5000/api/cable', connectImmediately: true };
createApp(App) .use(store) .use(router) .use(ActionCableVue, actionCableVueOptions) .mount('#app');
| Parameters | Type | Default | Required | Description | | ------------------ | -------- | ----------- | ------------ | ---------------------------------------------------------------------------------------------------------- | | debug | Boolean |
false| Optional | Enable logging for debug | | debugLevel | String |
error| Optional | Debug level required for logging. Either
info,
error, or
all| | connectionUrl | String/Function |
null| Optional | ActionCable websocket server url. Omit it for the default behavior | | connectImmediately | Boolean |
true| Optional | ActionCable connects to your server immediately. If false, ActionCable connects on the first subscription. | | store | Object | null | Optional | Vuex store |
If you'd like to donate to support the continued development and maintenance of actioncable-vue, you can do so here.
If you want to listen to channel events from your Vue component, you need to either add a
channelsobject in the Vue component, or if you're using
vue-class-componentdefine a
channelsproperty. Each defined object in
channelswill start to receive events provided you subscribe correctly.
new Vue({ data() { return { message: 'Hello world' }; }, channels: { ChatChannel: { connected() {}, rejected() {}, received(data) {}, disconnected() {} } }, methods: { sendMessage: function() { this.$cable.perform({ channel: 'ChatChannel', action: 'send_message', data: { content: this.message } }); } }, mounted() { this.$cable.subscribe({ channel: 'ChatChannel', room: 'public' }); } });
Alternative definition for
vue-class-componentusers.
@Component export default class ChatComponent extends Vue { @Prop({required: true}) private id!: string;get channels() { return { ChatChannel: { connected() { console.log('connected'); }, rejected() {}, received(data) {}, disconnected() {} } }; }
sendMessage(){ this.$cable.perform({ channel: 'ChatChannel', action: 'send_message', data: { content: this.message } }); }
async mounted() { this.$cable.subscribe({ channel: 'ChatChannel', room: 'public' }); } }
Define a
channelsobject in your component matching the action cable server channel name you passed for the subscription.
new Vue({ channels: { ChatChannel: { connected() { console.log('I am connected.'); } } }, mounted() { this.$cable.subscribe({ channel: 'ChatChannel' }); } });
ActionCableVue automatically uses your ActionCable server channel name if you do not pass in a specific channel name to use in your
channels. It will also override clashing channel names.
new Vue({ channels: { chat_channel_public: { connected() { console.log('I am connected to the public chat channel.'); } }, chat_channel_private: { connected() { console.log('I am connected to the private chat channel.'); } } }, mounted() { this.$cable.subscribe({ channel: 'ChatChannel', room: 'public' }, 'chat_channel_public' ); this.$cable.subscribe({ channel: 'ChatChannel', room: 'private' }, 'chat_channel_private' ); } });
// Conversations.vuenew Vue({ methods: { openConversation(conversationId){ this.$router.push({name: 'conversation', params: {id: conversationId}); } } });
// Chat.vuenew Vue({ channels: { computed: [{ channelName() { return
${this.$route.params.conversationId}
; }, connected() { console.log('I am connected to a channel with a computed name.'); }, rejected() {}, received(data) {}, disconnected() {} }] }, mounted() { this.$cable.subscribe({ channel: this.$route.params.conversationId }); } });
When your component is destroyed ActionCableVue automatically unsubscribes from any channel that component was subscribed to.
new Vue({ methods: { unsubscribe() { this.$cable.unsubscribe('ChatChannel'); } }, mounted() { this.$cable.subscribe({ channel: 'ChatChannel' }); } });
ActionCableVue automatically connects to your Action Cable server if
connectImmediatelyis not set to
falseduring setup. If you do set
connectImmediatelyto
falseyou can manually trigger a connection to your ActionCable server with
this.$cable.connection.connect.
new Vue({ methods: { connectWithRefreshedToken(token) { // You can optionally pass in a connection URL string // You can optionally pass in a function that returns a connection URL // You can choose not to pass in anything and it'll reconnect with the connection URL provided during setup. this.$cable.connection.connect(`ws://localhost:5000/api/cable?token=${token}`); } } });
new Vue({ methods: { disconnect() { this.$cable.connection.disconnect(); } } });
Requires that you have a method defined in your Rails Action Cable channel whose name matches the action property passed in.
new Vue({ channels: { ChatChannel: { connected() { console.log('Connected to the chat channel'); }, received(data) { console.log('Message received'); } } }, methods: { sendMessage() { this.$cable.perform({ channel: 'ChatChannel', action: 'send_message', data: { content: 'Hi' } }); } }, mounted() { this.$cable.subscribe({ channel: 'ChatChannel' }); } });
ActionCableVue has support for Vuex. All you have to do is setup your store correctly and pass it in during the ActionCableVue plugin setup.
// store.jsimport Vue from 'vue'; import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({ state: { }, mutations: { sendMessage(state, content){ this.$cable.perform({ action: 'send_message', data: { content } }) } }, actions: { sendMessage({ commit }, content) { commit('sendMessage', content) } } });
import store from './store'; import Vue from 'vue'; import ActionCableVue from 'actioncable-vue';Vue.use(ActionCableVue, { debug: true, debugLevel: 'all', connectionUrl: process.env.WEBSOCKET_HOST, connectImmediately: true, store });
ActionCableVue works just fine with Nuxt.JS. All you need to do is set it up as a client side plugin.
// /plugins/actioncable-vue.jsimport Vue from 'vue'; import ActionCableVue from 'actioncable-vue';
if (process.client) { Vue.use(ActionCableVue, { debug: true, debugLevel: 'all', connectionUrl: process.env.WEBSOCKET_HOST, connectImmediately: true }); }
Don't forget to register your plugin.
// nuxt.config.js /* ** Plugins to load before mounting the App */ plugins: [{ src: '@/plugins/actioncable-vue', ssr: false }];