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 ...
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 và :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 = " Click 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! Try 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/