websocket-rails

Plug and play WebSocket support for ruby on rails.

View project onGitHub

Websocket-Rails

Build Status

Now with streaming HTTP support for improved browser compatibility

The Present

Start treating client side events as first class citizens inside your Rails application with a built in WebSocket server. Sure, WebSockets aren't quite universal yet. That's why we also support streaming HTTP. Oh, and if you don't mind running a separate process, you can support just about any browser through Flash sockets without changing a line of code.

The Future

The long term goal for this project is simple. Reduce the need to move application logic on to the client while still providing the same level of interaction and responsiveness users have grown to expect from a modern web application. We hope to isolate the responsibility of JavaScript to the presentation layer and keep business logic nicely organized on the server.

Installation and Usage Guides

A Brief Tour

Map events to controller actions using an Event Router.

WebsocketRails::EventMap.describe do
  namespace :tasks do
    subscribe :create, :to => TaskController, :with_method => :create
  end
end

Trigger events using our JavaScript client.

var task = {
  name: 'Start taking advantage of WebSockets',
  completed: false
}

var dispatcher = new WebSocketRails('localhost:3000/websocket');

dispatcher.trigger('tasks.create', task);

Handle events in your controller.

class TaskController < WebsocketRails::BaseController
  def create
    # The `message` method contains the data received
    task = Task.new message
    if task.save
      send_message :create_success, task, :namespace => :tasks
    else
      send_message :create_fail, task, :namespace => :tasks
    end
  end
end

Receive the response in the client.

dispatcher.bind('tasks.create_success', function(task) {
  console.log('successfully created ' + task.name);
});

Or just attach success and failure callbacks to your client events.

var success = function(task) { console.log("Created: " + task.name); }

var failure = function(task) {
  console.log("Failed to create Product: " + product.name)
}

dispatcher.trigger('products.create', success, failure);

Then trigger them in your controller:

def create
  task = Task.create message
  if task.save
    trigger_success task
  else
    trigger_failure task
  end
end

If you're feeling truly lazy, just trigger the failure callback with an exception.

def create
  task = Task.create! message
  trigger_success task # trigger success if the save went alright
end

That controller is starting to look pretty clean.

Now in the failure callback on the client we have access to the record and the errors.

var failureCallback = function(task) {
  console.log( task.name );
  console.log( task.errors );
  console.log( "You have " + task.errors.length + " errors." );
}

Channel Support

Keep your users up to date without waiting for them to refresh the page. Subscribe them to a channel and update it from wherever you please.

Tune in on the client side.

channel = dispatcher.subscribe('posts');
channel.bind('new', function(post) {
  console.log('a new post about '+post.title+' arrived!');
});

Broadcast to the channel from anywhere inside your Rails application. An existing controller, a model, a background job, or a new WebsocketRails controller.

latest_post = Post.latest
WebsocketRails[:posts].trigger 'new', latest_post

Private Channel Support

Need to restrict access to a particular channel? No problem. We've got that.

Private channels give you the ability to authorize a user's subscription using the authorization mechanism of your choice.

Just tell WebsocketRails which channels you would like to make private and how you want to handle channel authorization in the event router by subscribing to the websocket_rails.subscribe_private event.

WebsocketRails::EventMap.describe do
  private_channel :secret_posts

  namespace :websocket_rails
    subscribe :subscribe_private, :to => AuthenticationController, :with_method => :authorize_channels
  end

Or you can always mark any channel as private later on.

WebsocketRails[:secret_posts].make_private

On the client side, you can use the dispatcher.subscribe_private() method to subscribe to a private channel.

Read the Private Channel Wiki for more information on dealing with private channels.

Development

This gem is created and maintained by Dan Knox and Kyle Whalen under the MIT License.

Brought to you by:

Three Dot Loft LLC