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 9 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
: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ạ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