#38 ActionCable - Part 2 - More Complex Example

Summary

Extending the previous episode, we look into making a realtime poll application where users can get live feedback on voting.
view websockets render javascript rails 5:10

Resources

Summary

# vote.html.erb
<legend>Vote</legend>

<% powers = [ ['Telekenisis', :telekenisis], ['Mind Control', :mind_control], ['Flying', :flying], ['Invisibility', :invisibility], ['Super Strength', :super_strength]] %> <%= simple_form_for :vote do |f| %> <div class='form-group'> <%= f.label :power, label: 'Which super power would you choose?', class: 'col-xs-4' %> <div class='col-xs-8'> <%= f.input_field :power, as: :radio_buttons, collection: powers %> </div> </div> <% end %> <legend>Results</legend> <div class='results'> <% powers.each do |label, symbol| %> <%= content_tag :div, class: symbol do %> <span><%= label %></span> <span class='count'> <div class="progress"> <div class="progress-bar progress-bar-success" role="progressbar">0</div> </div> </span> <% end %> <% end %> </div>

# vote.js
App.vote = App.cable.subscriptions.create("VoteChannel", {
  connected: function() {
  },

  disconnected: function() {
  },

  received: function(data) {
    var power =  data['power'];
    var count = parseInt($('.' + power + ' .count').text());  
    if (data['method'] == 'add') {
      $('.results ' + '.' + power + ' .count .progress-bar').html(count + 1);
    } else if (data['method'] == 'subtract') {
      $('.results ' + '.' + power + ' .count .progress-bar').html(count - 1);
    }

    var total_count = 0;
    $('.count .progress-bar').each( function(){
      total_count = total_count + parseInt($(this).text());
    })

    $('.count .progress-bar').each( function(){
      $(this).css('width',parseInt($(this).text()) / total_count * 100 + '%');
    })
  },

  voted: function(power) {
    return this.perform('voted', { power: power });
  },

  reduce: function(power) {
    return this.perform('reduce', { power: power });
  }
});

# vote_channel.rb
class VoteChannel < ApplicationCable::Channel
  def subscribed
    stream_from "vote"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def voted(data)
    ActionCable.server.broadcast 'vote', power: data['power'], method: 'add'
  end

  def reduce(data)
    ActionCable.server.broadcast 'vote', power: data['power'], method: 'subtract'
  end
end

# visitors.coffee
vote = ->
  clicks = new Array
  $('input[type=radio]').change ->
    clicks.push @value
    App.vote.voted @value
    App.vote.reduce clicks[clicks.length - 2]

$(document).on 'turbolinks:load', vote

# visitors.js
// Javascript version of visitors.coffee
var vote = function(){
  var clicks = new Array();
  $('input[type=radio]').change(function() {
    clicks.push(this.value);
    App.vote.voted(this.value);
    App.vote.reduce(clicks[clicks.length - 2]);
  });
}
$(document).on('turbolinks:load', vote)