Sử dụng gem WebsocketRails để xây dựng ứng dụng thời gian thực
Bài đăng này đã không được cập nhật trong 10 năm
1. Giới thiệu
WebSockets là một kỹ thuật Reverse Ajax mới hơn Comet, cho phép các kênh giao tiếp song song hai chiều và hiện đã được hỗ trợ trong nhiều trình duyệt (Firefox, Google Chrome và Safari). Gem WebsocketRails là một cài đặt trên Rails của WebSockets, cho phép ta xây dựng ứng dụng thời gian thực.
2. Cài đặt và sử dụng
Cài đặt
Thêm dòng sau  vào file Gemfile
gem "websocket-rails"
và chạy câu lệnh
$ bundle install
Tiếp theo chạy generator
$ rails g websocket_rails:install
Routes
Lệnh chạy generator ở trên sẽ tạo file events.rb trong thư mục config.Ta có thể chỉnh sửa file này để map client side events với các actions trong controller. 
Ta sử dụng subcribe method để subscribe 1 event cho 1 action cụ thể trong controller.
Để chỉ định action ta có thể dùng 1 trong 2 cách:
- dùng hash với keys :tovà:with_method
- hoặc sử dụng xâu với cú pháp "controller_name#method_name",controller_namelà tên controller class không có hậu tốControllervà dưới dạngunderscore_case
subscribe :event_name, :to => EventController, :with_method => :action_method
# or the equivalent
subscribe :event_name, 'event#action_method'
Open a socket connection
Đầu tiên ta cần mở 1 socket connection từ phía client
var dispatcher = new WebSocketRails('localhost:3000/websocket');
Trigger events
Trigger events dùng JavaScript client.
var task = {
  name: 'Start taking advantage of WebSockets',
  completed: false
}
dispatcher.trigger('tasks.create', task);
Handle events
Xử lí event trong 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
Nhận response ở client
dispatcher.bind('tasks.create_success', function(task) {
  console.log('successfully created ' + task.name);
});
Ngoài ra cũng có thể gán success and failure callbacks ở client events, rồi sau đó trigger ở controller
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);
def create
  task = Task.create message
  if task.save
    trigger_success task
  else
    trigger_failure task
  end
end
Sending an Event to a Specific Client (User)
Ta cũng có thể gửi event cho 1 client được chỉ định nhờ UserManager được gọi thông qua WebsocketRails.users.Method này có thể được gọi bên ngoài websocket controller
WebsocketRails.users[myUser.id].send_message('new_notification', {:message => 'you\'ve got an upvote '})
Method send_message có 2 arguments, tên event được trigger và data object được gửi kèm.
3. Example Application
Ví dụ áp dụng cho bài toán tạo lịch biểu, mỗi event có thể có nhiều members, cần thông báo cho member khi được mời vào 1 event, hay khi bị xóa khỏi 1 event. Ta gửi message cho member từ trong model.
class User < ActiveRecord::Base
  has_many :schedules
  has_and_belongs_to_many :events, class_name: Schedule.name
end
class Schedule < ActiveRecord::Base
  belongs_to :user
  has_and_belongs_to_many :members, class_name: User.name,
    after_add: :invite, after_remove: :reject
  def invite member
    WebsocketRails.users[member.id].send_message "invited", id
  end
  def reject member
    WebsocketRails.users[member.id].send_message "rejected", id
  end
end
Có thể kết hợp dùng Notification ở phía client để ứng dụng phong phú hơn:
if (Notification.permission !== "granted")
    Notification.requestPermission();
  var dispatcher;
  var host = location.host;
  var origin = location.origin;
  var title, body, link;
  var addition = "\nClick for details";
  dispatcher = new WebSocketRails(host + "/websocket");
  dispatcher.bind("invited", function(schedule_id) {
    title = "Invitation";
    message = "You were invited to participate an event.";
    body = message + addition;
    link = origin + "/schedules/" + schedule_id.toString();
    notifyMe(title, body, link);
  });
  dispatcher.bind("rejected", function(schedule_id) {
    title = "Rejected";
    message = "You were rejected from an event.";
    body = message + addition;
    link = origin + "/schedules/" + schedule_id.toString();
    notifyMe(title, body, link);
  });
});
function notifyMe(title, body, link){
  if(! ("Notification" in window) ){
    alert("Desktop notifications not available in your browser!\nTry Chrome");
    return;
  }
  if (Notification.permission !== "granted")
    Notification.requestPermission();
  if (Notification.permission === "granted") {
    var option = {
      body:body,
      dir:"auto"
    }
    var notification = new Notification(title,option);
    notification.onclick = function () {
      notification.close();
      window.open(link);
    };
    setTimeout(function(){
      notification.close();
    },10000);
  }
Tham khảo
http://websocket-rails.github.io/ 
http://altoros.github.io/2013/websocket-rails/
All rights reserved
 
  
 