Rudi Thiel
Rudi Thiel

Reputation: 2551

Rails - Call ajax request when database is updated

So I'm creating a basic jackpot betting site for fun and it allows users to put money into a pot and then based on the percentage of money each user puts in it randomly picks a winner. It's working fine at the moment but I feel like the way I'm updating the jackpot page with ajax is really bad. At the moment I have javascript that makes an ajax request each second to get the pot info (size of the pot, players, etc..). I feel like there is a much better way to do this. Is it possible to only make an ajax call when the database is updated? Thanks!

My javascript at the moment:

setInterval(update, 1000);

function update() {
getPotID();
$.ajax({
    type: "POST",
    url: "/jackpot/update/" + potID,
    complete: function(response) {
      $('.live-jackpot').html(response.responseText);
      getPotInfo();
    },
    error: function(xhr, status,error) {
      console.log("Error");
    }
}); 
}

Upvotes: 1

Views: 523

Answers (1)

fabOnReact
fabOnReact

Reputation: 5942

as said from 7urkm3n, ActionCable has great advantage for this functionality.

Right now you are writing Javascript code that is executed on the client side. Every user that will start a GET http request to your site, will load that javascript files. They will start performing POST request every second to your backend server.

ActionCable is a websocket preinstalled in Rails 5. This means that to configure the notifications with ActionCable and Rails 5, you already have installed everything in your app (if you are using rails 5), you just need to install Redis on your local machine for testing the app in development.

I am not an expert, my understanding is that you use a specific database called redis to store the information about the subscription. I quote a useful article

So PubSub is this concept that Redis and Postgres and a few other things supports, and basically you have this ability to have Channels and the ability to subscribe (and receive those messages) and publish to those channels and anyone listening will then receive those messages.

An example of this is a ChatroomChannel, you could have people publishing messages to the ChatroomChannel and anyone who was subscribed to the ChatroomChannel would receive the broadcast from the channel with the websocket.

This is something you are missing, this way you could only find which users are actually on the playing page and which users are just browsing around, based on this ActionCable creates a channel to communicate between server and client and then creates a subscription to distinguish users that are actually on the playing page and those that left and should not be anymore notified

I quote another useful article

Before we dive into some code, let's take a closer look at how Action Cable opens and maintains the WebSocket connection inside our Rails 5 application.

Action Cable uses the Rack socket hijacking API to take over control of connections from the application server.

For every instance of your application that spins up, an instance of Action Cable is created, using Rack to open and maintain a persistent connection, and using a channel mounted on a sub-URI of your main application to stream from certain areas of your application and broadcast to other areas.

so every user that connects, ActionCable creates a channel that uses a specific url localhost:3000/cable to communicate between server and client (browser)

Action Cable offers server-side code to broadcast certain content (think new messages or notifications) over the channel, to a subscriber. The subscriber is instantiated on the client-side with a handy JavaScript function that uses jQuery to append new content to the DOM.

This means that the server can call the client with parameters and change the page with jquery functions. For ex. appending a div, with a new message.

In my app https://sprachspiel.xyz I do the following in the MessagesController#create

ActionCable.server.broadcast 'messages',
message: message.content,
user: message.user.name,
chatroom_id: message.chatroom_id,        
lastuser: chatroom.messages.last(2)[0].user.name
head :ok

so basically, I have my message in my controller and I can update the client by using the ActionCable.server.broadcast function

then in my asset pipeline file /app/assets/javascripts/channels/messages.js I have the following code that trigger the change in the browser adding the message

App.messages = App.cable.subscriptions.create('MessagesChannel', {      
  received: function(data) {
      $('#messages').append(this.renderMessage(data));
  },
  renderMessage: function(data) {
    return "<br><p> <strong>" + data.user + ": </strong>" + data.message + "</p>";
  }
});

I build an app called https://sprachspiel.xyz that is an actioncable app, this is the github page for the project, on my portfolio you can read more info about my app, so please ask me anything, I'll be happy to look into it!

Good luck Fabrizio

Upvotes: 1

Related Questions