Rails 6.1 ActionCable
rails new cableguy --database=mysql
cd cableguy
rails g resource libraryBook title status status_date:datetime
rails db:create
rails db:migrate
libary_books = LibraryBook.create([{title: 'Moby Dick', status: 'on-shelf'}, {title: 'Cruel Shoes', status: 'on-shelf'}])
rails db:seed
root "library_books#index"
library_books_controller.rb
def index
@books = LibraryBook.all
end
<h1>Our Books</h1>
<% if [email protected]? %>
<% for book in @books %>
<% end %>
<% end %>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity_no="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js" integrity_no="sha384-LtrjvnR4Twt/qOuYxE721u19sVFLVSA4hf/rRt6PrZTmiPltdZcI7q7PXQBYTKyf" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity_no="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<div class='container'>
<%= yield %>
</div>
<div class='row'>
<div class='col'>
<%= book.title%>
</div>
<div class='col'>
<%= book.status.titleize%>
</div>
</div>
app/views/library_books/_one_book.html.erb
<div class='row'>
<div class='col'>
<%= book.title%>
</div>
<div class='col'>
<%= book.status.titleize%>
</div>
</div>
<%= render partial: "one_book", locals: {book: book} %>
######## end of the basics ########
yarn add stimulus
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"
const application = Application.start()
const context = require.context("../controllers", true, /\.js$/)
application.load(definitionsFromContext(context))
import { Controller } from "stimulus"
import consumer from '../channels/consumer';
export default class extends Controller {
static targets = ['bookstatus']
connect() {
console.log('Will create subscription to: channel: "LibraryBookStatusChannel" library_book_id: ' + this.data.get('bookid'));
this.channel = consumer.subscriptions.create({ channel: 'LibraryBookStatusChannel', library_book_id: this.data.get('bookid') }, {
connected: this._cableConnected.bind(this),
disconnected: this._cableDisconnected.bind(this),
received: this._cableReceived.bind(this),
});
}
_cableConnected() {
// Called when the subscription is ready for use on the server
console.log('_cableConnected');
}
_cableDisconnected() {
// Called when the subscription has been terminated by the server
console.log('_cableDisconnected');
}
_cableReceived(data) {
console.log('_cableReceived');
// Called when there's incoming data on the websocket for this channel
this.bookstatusTarget.innerHTML = data.message;
}
}
<div data-controller="book-status" data-book-status-bookid="<%= book.id %>">
<div data-book-status-target='bookstatus'>
<%= render partial: "one_book", locals: {book: book} %>
</div>
</div>
class LibraryBookStatusChannel < ApplicationCable::Channel
def subscribed
# the param name is set in the stimulus controller
stream_from "LibraryBookStatusChannel:#{params[:library_book_id]}"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
stop_all_streams
end
end
after_commit :broadcast_me
def broadcast_me
ActionCable.server.broadcast "LibraryBookStatusChannel:#{id}", {
status: status.titleize,
message: LibraryBooksController.render(partial: 'one_book', locals: { book: self }).squish
}
end
in Gemfile
gem 'redis'
development:
adapter: redis
<%= action_cable_meta_tag %>