baron816
baron816

Reputation: 701

Rails 4.2 What's currently the best way to incorporate instant messaging in an app?

I've been reading that Rails 5 (anyone know when that will be release?) will be incorporating support for websockets that will make instant messaging easier to incorporate. But I'm trying to set something up now for an fairly built up app. If all goes well, I could have quite a number of users soon, so it will need to scale as well.

I've looked at Ryan Bates's Private Pub which is kind of old, Heroku's websocket example (I'm deployed on Heroku), Websocket-rails, actioncable, and maybe a few others. Most look pretty involved, so I'm wondering what my best option is, or if Rails 5 will be out soon and I should just wait for that?

Thanks.

Upvotes: 1

Views: 2152

Answers (2)

Pierre Pretorius
Pierre Pretorius

Reputation: 2909

Rails 5 has been released. I recommend you upgrade and go with actioncable.

In the long run it should be the best option as it will be part of the Rails core and it is developed, used and maintained by Basecamp. They will invest enough effort to make sure it is stable, scalable and accepted by the community.

Upvotes: 0

Myst
Myst

Reputation: 19221

I'm biased towards Plezi, which is built for scaling (using Redis) and can be used to easily add websocket support to your existing web-app... but than again, I might not be objective about it.

There are two ways to run Plezi within Rails - either merging the apps/servers (using the Iodine HTTP/Websocket server) or using Redis to sync the two apps.

Both ways are easy to set up.

To use Plezi within your Rails app, add plezi to your Gemfile and remove any references to 'thin' or 'puma' or any other server from your Gemfile - this should allow Iodine to take over automatically. Than place Plezi.app as a middleware in your app.

You can either include a pre-made Plezi app by requiring it's files, or - even easier - you could write the code into one of the Rails files (maybe using the 'initializers', 'helpers' or 'models' folders).

Try adding the following code for a chatroom server:

require 'plezi'

# do you need automated redis support?
# require 'redis'
# ENV['PL_REDIS_URL'] = "redis://user:password@localhost:6379"

class BroadcastCtrl
    def index
        # we can use the websocket echo page to test our server, 
        # just remember to update the server address in the form.
        redirect_to 'http://www.websocket.org/echo.html'
    end
    def on_message data
        # try replacing the following two lines are with:
        # self.class.broadcast :_send_message, data
        broadcast :_send_message, data
        response << "sent."
    end
    def _send_message data
        response << data
    end
end

route '/broadcast', BroadcastCtrl

This allows us to inject some Rails magic into Plezi and some Plezi magic into Rails... For instance, it's easy to save a user's websocket UUID and send them updates:

require 'plezi'

# do you need automated redis support?
# require 'redis'
# ENV['PL_REDIS_URL'] = "redis://user:password@localhost:6379"

class UserNotifications
    def on_open
        get_current_user.websocket_uuid = uuid
        get_current_user.save
    end
    def on_close
        # wrap all of the following in a transaction, or scaling might
        # create race conditions and corrupt UUID data
        return unless UsersController.get_current_user.websocket_uuid == uuid
        get_current_user.websocket_uuid = nil 
        get_current_user.save
    end
    def on_message data
         # get data from user and use it somehow
    end
    protected
    def get_current_user
         # # use your authentication system here, maybe:
         # @user ||= UserController.auth_user(cookies[:my_session_id])
    end
    def send_message data
        response << data
    end
end

route '/', UserNotifications

# and in your UserController 

def UserController < ApplicationController
    def update
        # your logic and than send notification:
        data = {}
        UserNotifications.unicast @user.websocket_uuid, :send_message, data.to_json
    end
end

Upvotes: 2

Related Questions