+1

Sử dụng gem WebsocketRails để xây dựng ứng dụng thời gian thực

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 :to:with_method
  • hoặc sử dụng xâu với cú pháp "controller_name#method_name", controller_name là tên controller class không có hậu tố Controller và dưới dạng underscore_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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí