Ruby Publish/Subscribe Tutorial for Realtime Apps

PubNub utilizes a Publish/Subscribe model for real-time data streaming and device signaling which lets you establish and maintain persistent socket connections to any device and push data to global audiences in less than ¼ of a second.

The atomic components that make up a data stream are API Keys, Messages, and Channels.

To build an application that leverages the PubNub Network for Data Streams with Publish and Subscribe, you will need PubNub API Keys which we provide when you Sign-Up.

You will need at the minimum a subscribe_key and publish_key. If a client will only subscribe, and not publish, then the client only need to initialize with the subscribe_key. For clients who will be publishing only, or publishing and subscribing (a client can both publish and subscribe), it will need to initialize with both the subscribe_key and the publish_key.

You only need to supply the publish_key to clients that will publish (send) data to your application over the PubNub network. A read-only client for example would not need to initialize with this key.

 

Although a secret_key is also provided to you along with your publish and subscribe keys in the admin portal, it is not required for plain-old publish and subscribe. You’ll only need the secret_key if you are using PAM functionality, which we discuss more in the PAM Feature Tutorial.

A message consists of a channel, and its associated data payload. A publishing client publishes messages to a given channel, and a subscribing client receives only the messages associated with the channels its subscribed to.

PubNub Message payloads can contain any JSON data including Booleans, Strings, Numbers, Arrays, and Objects. Simply publish the native type per your platform, and the clients will JSON serialize the data for you. Subscribers will automatically deserialize the JSON for you into your platform’s associated native type.

When creating a message, keep these limits in mind:

  • Maximum message size is 32KB
  • The message size includes the channel name
  • The message size is calculated after all URL encoding and JSON serialization has occured. Depending on your data, this could add > 4X the original message size.

Keeping your messages < 1.5KB in size will allow them to fit into a single TCP packet!

Channels are created on-the-fly, and do not incur any additional charges to use one or many in your application. When you create a PubNub application, all messages will be associated with a channel.

In a unicast (AKA 1:1) design pattern, the channels can be unique for each client in one-to-one communication. For example, user1 subscribes to user1-private, and user2 subscribes to user2-private. Using this pattern, each client listens on a channel which only relevant data to that client is sent.  It has the advantage of minimal network usage (each client receives only the data it needs) and minimal processing (no need for filtering unneeded data).

PubNub Galaxy                                                                                                                            

In a multicast (AKA 1:Many) design pattern, a “public” (AKA ‘system’, ‘global’, or ‘admin’) channel is used for global communications amongst all clients. For example, building off our previous example, while a user can speak to any other user on their “private” channel, since each client in the application is listening on their private channel AND the public channel, they can receive on either. When receiving a message on the ‘public’ channel, it may or may not be relevant for that particular receiving client -- to get around this, the client can filter on some sort of ‘key’, allowing them to selectively process messages with specific interest to them.

PubNub Pulse

In many cases, based on the use case of your application, the pattern you choose may be unicast, multicast, or a combination. There is no right or wrong pattern to implement, but based on your use case, there may be an optimal, most efficient pattern.

Since the text length of the channel name is counted as part of the entire message, and as such, as part of the maximum message length, it is best to keep the channel name as short as efficiency and utility allows.

Channel names are UTF-8 compatible. Prohibited chars in a channel name are:

  • comma: ,
  • slash: /
  • backslash: \
  • period: .
  • asterisks: *
  • colon: :
  • Install the PubNub Ruby gem.
  • PUBNUB.new() - instantiate a PubNub instance.
  • subscribe() - additively subscribe to a specific channel.
  • publish() - send a message on a specific channel.
  • unsubscribe() - additively unsubscribe to a specific channel.
require 'pubnub'

If this PubNub instance will only be subscribing, you only need to pass the subscribe_key to initialize the instance. If this instance will be subscribing and publishing, you must also include the publish_key parameter.

pubnub = Pubnub.new(
  publish_key: 'demo',
  subscribe_key: 'demo'
)

The channel the messages will be published over is called my_channel. And for this example, we want the same instance to both publish and subscribe. To do this, we’ll publish a message to the channel, but only after we’re sure we’ve first successfully subscribed to the channel.

The publish() and subscribe() methods are pretty simple to use. For both publish() and subscribe(), the channel attribute defines the channel in use.

For subscribe() the message callback is where received messages are called-back to:

pubnub.subscribe(
  channel: 'my_channel'
) do |envelope| 
  puts envelope.message
end
 

NOTE: During your application’s lifecycle, you can call subscribe() repeatedly to additively subscribe to additional channels.

For publish(), the message attribute contains the data you are sending.

pubnub.publish(
  channel: 'my_channel',
  message: 'Hello from PubNub Ruby SDK!'
) do |envelope| 
  puts envelope.parsed_response
end
 

The above code demonstrates how to subscribe, and how to publish. But what if your use-case requires that client instance not only subscribes and publishes, but also that its guaranteed to start publishing only AFTER it’s successfully subscribed? -- In other words, you want to guarantee it receives all of its own publishes?

The Ruby client SDK, like many of the PubNub SDKs, is asynchronous -- publish() can, and most likely will, fire before the previously executed subscribe() call completes. The result is, for a single-client instance, you would never receive (via subscribing) the message you just published, because the subscribe operation did not complete before the message was published.

To get around this common case, we can take advantage of the optional ‘connect’ callback in the subscribe method.

pubnub = Pubnub.new(
  subscribe_key: 'sub-key', 
  publish_key: 'pub-key', 
  connect_callback: lambda {|msg| pubnub.publish(channel: 'my_channel', message: 'Hello from PubNub Ruby SDK!!', http_sync: true)}
)
 
pubnub.subscribe(channel: 'my_channel') do |envelope|
  puts envelope.message
end
 

By following this pattern on a client that both subscribes and publishes when you want to be sure to subscribe to your own publishes, you’ll never miss receiving a message.

While you are subscribed to a channel, you will continue to receive messages published to that channel. To stop receiving messages on a given channel, you must unsubscribe() from the channel.

pubnub.unsubscribe(
  channel: 'my_channel'
) do |envelope|
  puts envelope.message
end

Like subscribe(), unsubscribe() can be called multiple times to successively remove different channels from the active subscription list.