Skip to content

WebsocketRails Controllers

MhdSyrwan edited this page Oct 15, 2014 · 13 revisions

Similar to standard Rails requests, each event processed by the server is handled by a fresh instance of your controller object. Any instance variables set in your controller will be wiped out after the action for an event finishes processing. This works great in the standard Rails request/response cycle. However, it is not always convenient for dealing with long running persistent connections such as WebSocket clients. Because of this, we provide our own Controller DataStore object, accessible in a WebsocketRails controller, to make it easier to temporarily store data between events. This is explained further in the DataStore Wiki.

Initializing the Controller

Do not override the initialize method in your class to set up. Instead, define an initialize_session method and perform your set up there. The initialize_session method will be called the first time a controller is subscribed to an event in the event router. Values added to the controller data store from inside the initialize_session method will be available throughout the course of the server lifetime.

class ChatController < WebsocketRails::BaseController
  def initialize_session
    # perform application setup here
    controller_store[:message_count] = 0
  end
end

Triggering Events on the Client

You can trigger an event on the client using the send_message method. The send_message method takes two arguments, the event name to trigger, and an object to send along with the event.

new_message = {:message => 'this is a message'}
send_message :event_name, new_message

You would handle this event on the client side with the following JavaScript (assuming you already have a dispatcher initialized):

dispatcher.bind('event_name', function(data) {
  console.log(data.message); // would output 'this is a message'
});

Triggering the Success and Failure Callbacks on the Client Event

If the current event was triggered by the client with success and failure callbacks attached, you can execute them from your controller action using the trigger_success and trigger_failure methods.

Both methods can take an optional object that will be passed to the callback functions on the client.

def awesomeness_approval
  if message[:awesomeness] > 5
    trigger_success {:message => 'awesome level is sufficient'}
  else
    trigger_failure {:message => 'awesome level is insufficient'}
  end
end

Now you can trigger the awesomeness_approval event on the JavaScript client and easily handle the result.

var success = function(response) {
  console.log("You are awesome because: "+response.message);
}

var failure = function(response) {
  console.log("You are not very awesome because: "+response.message);
}

var message = { awesomeness: 4 }
dispatcher.trigger('awesomeness_approval', message, success, failure); 

Sending an Event to a Specific Client (User)

You can send an event to a specific client using the UserManager which can be accessed via WebsocketRails.users.

WebsocketRails.users[myUser.id].send_message('new_notification', {:message => 'you\'ve got an upvote '})

Note: you can use this method outside the websocket controller too.

Broadcasting Events to all Clients

You can trigger events on all connected clients at once using the broadcast_message method. It takes the same arguments as the send_message. If you wish to broadcast to a subset of connected clients, you can use Channels.

new_comment = Comment.latest
broadcast_message :new_comment, new_comment

Triggering Namespaced Events

Namespaced events are triggered from a controller by passing the :namespace option to the send_message or broadcast_message methods.

products = Product.find(:all, :limit => 10)
send_message :new_list, products, :namespace => 'products'

You would bind to this event on the client with the following JavaScript:

dispatcher.bind('products.new_list', function(products) {
  console.log('we just received ' + products.size + ' new products!');
});

Event Callbacks

Event callbacks are similar to the before_filter/after_filter/around_filter (and in Rails 4 before_action/after_action/around_action) methods in Rails. You can attach a block of code to be run when a particular event is triggered within a controller or when any action inside the controller is called.

The following callback will be called any time the new_event event is triggered:

class EventController < WebsocketRails::BaseController
  before_filter :only => :new_event do
    puts "new_event was called"
  end

  def new_event
    # handle event
  end
end

If you want to execute a block before any action in the controller is called regardless of the event, just leave off any arguments.

class EventController < WebsocketRails::BaseController
  before_filter do
    puts "an event handled by this controller was called"
  end
end

And come more examples:

class EventController < WebsocketRails::BaseController
  before_filter :ensure_logged_in!
  after_filter do
    puts "perform post-action work"
  end
  around_filter :time_request

  def ensure_logged_in!
    if current_user.nil?
      current_user = User.new
    end
  end

  def time_request
    start = Time.now
    yield
    delta = Time.now - start
    puts "Action took #{delta.to_f} seconds"
  end
end

Callbacks will be executed in the same order as they are subscribed.

Please see Rails documentation of Filters for more examples.

Standard Rails Controller Helpers

You can use all of the standard Rails controller helper methods such as url_for inside of a WebsocketRails Controller. You can also use controller helper methods provided by gems like Devise.