Chat App by Rails with gem Private Pub

1. Lời mở

Chắc chắn không ít bạn developer đang và đang sử dụng rất nhiều các dịch vụ chat trực tuyến cho cả công việc lẫn giải trí (chatwork, slack, skype, facebook). Vậy tại sao bạn không thử tự mình làm 1 trang web tương tự như vậy(ý mình chỉ là chức năng chat trực tuyến thôi, chứ muốn pro như mấy trong to to trên thì chúc ta cần phải học thêm nhiều thứ nữa). Ok, và không lan man nữa, sau đây mình sẽ chỉ cho bạn cách xây dựng 1 web chat bằng rails (với tốc độ ánh sáng :p)

2.Cài đặt

Dĩ nhiên không có gì nhanh và tiện bằng sử dụng gem trong rails, ở đây tôi sẽ dùng Gem Private Pub 1 trong những gem được vote khá nhiều đồng thời cũng dễ cài đặt và sử dụng. Gem này được Ryan Bates(một developer khá nổi tiếng rails gem như cancan, ruby-warrior... ) xây dựng dựa trên gem faye chuyên dùng để update real time(nếu thấy hứng thú về mảng này bạn có thể đọc và làm thử hoặc đợi bài viết sau của mình :p).

Giống như mọi gem khác, để cài đặt gem chúng ta khai báo trong file Gemfile

gem 'private_pub'

Sau đó chạy lệnh cài đặt gem trên terminal ở thư mục chứa app

$ bundle

$ rails g private_pub:install
      create  config/private_pub.yml
      create  private_pub.ru

đồng thời ta phải bật rack server lên bằng dòng lệnh

$ rackup private_pub.ru -s thin -E production
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:9292, CTRL+C to stop

Đồng thời, Chúng ta cần thêm 1 khai báo js //= require private_pub ở file application.js

# /app/assets/javascripts/application.js
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require private_pub
//= require_tree .

**3.Xây dựng app chat **

Ở đây mình sẽ hướng dẫn bạn tạo 1 web có chức năng chat đơn giản, nếu bạn muốn đẹp hơn thì có thể dùng boostrap

Đầu tiên là tạo 1 bảng message để lưu các tin nhắn trao đổi

rails g model message content:string name:string
rake db:migrate

Tạo Controller để xử lý việc tạo và hiển thị các message

#/app/controllers/messages_controller.rb
class MessagesController < ApplicationController
  def index
    @messages = Message.all
  end

  def create
    @message = Message.create! model_params
  end

  private
  def model_params
    params.require(:messages).permit :message, :name
  end
end

Sau đó tạo phần view để hiện phần chat

# /app/views/messages/index.html.erb
<h1>Chat</h1>

<ul id="chat">
  <%= render @messages %>
</ul>

<%= form_for Message.new, remote: true do |f| %>
  <%= f.text_field :name %>
  <%= f.text_field :content %>
  <%= f.submit "Send" %>
<% end %>
<%= subscribe_to "/messages/new" %>
#/app/views/messages/_message.html.erb
<li>
  <%= message.name.to_s + "said: " + message.content.to_s %>
</li>

Tiếp đó ta cần tạo file js có nhiệm vụ hiện các message mới về

#/app/views/messages/create.js.erb
<% publish_to "/messages/new" do %>
  $("#chat").append("<%= j render(@message) %>");
<% end %>

Ta sẽ có kết quả như sau:

376291b841547b5d27ea3434df077119.gif

Ok, đến đây mình sẽ giải thích 1 chút, chắc hẳn phần html có thể dễ dàng đọc hiểu được, chỉ có dòng

<%= subscribe_to "/messages/new" %>

có lẽ khiến nhiều bạn không hiểu.Hàm subscribe_to là 1 hàm của gem Private Pub giúp client có thể theo dõi 1 kênh nào đó và cập nhật thời gian thực dữ liệu từ kênh đó. Do đó ở đây ta có thể hiểu là phần view này sẽ theo dõi và lắng nghe từ kênh có tên "/messages/new".

Kế tiếp ở file js, ta có thể thấy hàm publish_to bao trùm toàn bộ phần code có nhiệm vụ hiện message mới và xóa phần nội dung vừa được submit trong phần chat. Nếu không có hàm publish_to thì đoạn code js này chỉ có tác dụng lên client thực thi request, còn ở các client khác thì sẽ ko có hiện tượng gì xảy ra và message mới chỉ hiện ra khi user load lại trang.

Tuy nhiên khi ta khai báo hàm publish_to "/messages/new" nghĩa là ta đã thông báo tới tất cả các client mà lắng nghe kênh "/messages/new" thực thi đoạn js trên => ở tất cả các client bật đoạn chat sẽ hiện ra message mới nhất.

**Note: ** Hàm publish_to không nhất thiết phải khai báo ở file js mà ta có thể khai báo ở tất cả các đoạn code ruby bằng cách sử dụng lệnh gọi PrivatePub.publish_to với 2 argument là tên kênh và đoạn code js bạn muốn chạy.

Ví dụ:

#/app/controllers/messages_controller.rb
def create
  @message = Message.create!(params[:message])
  PrivatePub.publish_to("/messages/new", "alert('#{@message.content}');")
end

Sau khi bạn thay xong đoạn code ở controler cũ bằng code mới trên, hãy thử chat và bạn sẽ thấy thông báo alert hiện lên ở mọi client.

Ngoài ra nếu bạn quen với việc sử dụng dữ liệu kiểu JSON truyền xuống cho client xử lý, thì hàm PrivatePub.publish_to đã hỗ trợ truyền value kiểu hash xuống client thông qua:

#/app/controllers/messages_controller.rb
def create
  @message = Message.create!(params[:message])
  PrivatePub.publish_to("/messages/new", message: @message)
end

Dồng thời bạn cũng phải viết 1 đoạn code js để xử lý dữ liệu nhận về.

Ví dụ:

#/app/assets/javascripts/messages.js.coffee
PrivatePub.subscribe "/messages/new", (data, channel) ->
  alert data.message.content

*** Nâng Cao ***

PrivatePub hỗ trợ chế độ cá nhân mặc định khi dùng. Tức là chỉ có những người được chúng ta cấp phép theo dõi kênh nào thì mới nhận được dữ liệu tù kênh đó, người ngoài sẽ không theo dõi được các kênh mà server ko cấp.

Ngoài ra chúng ta có thể chọn thời gian hết hạn cho mỗi lần theo dõi 1 kênh trong setting cho private pub ở file private_pub.yml

#/config/private_pub.yml
development:
  server: "http://localhost:9292/faye"
  secret_token: "secret"
test:
  server: "http://localhost:9292/faye"
  secret_token: "secret"
production:
  server: "http://example.com/faye"
  secret_token: "210eb617b6ce1c351d986a3185d34025cf42e5091a37502f18f595f7e8773853"
  signature_expiration: 3600 # one hour

như ở đây user sẽ không lắng nghe được kênh sau khi đa thoát ra 1 giờ.

chú ý: nếu bạn muốn xây 1 ứng dụng chat nội bộ thì bạn cần thay localhost với địa chỉ IP nội bộ máy của bạn ví dụ 192.168.1.123.

Và nếu bạn muốn chat private giữa 1 số người nhất định (sau khi có chức năng login) thì bạn hãy tạo kênh dựa theo id của các user đ, đồng thời các user chỉ có thể lắng nghe kênh chat có id của mình trong đó nhằm đảo bảo tính duy nhất và không có ai ngoài có thể vào được

Bài viết trên khá đơn giản nhằm giúp bạn hiểu và có thể áp dụng được chức năng chat trên app ROR, nên khá đơn giản nếu bạn muốn thực sự áp dụng vào hệ thông chạy thật thì ban có thể tham khảo bài viết sau đây, với đầy đủ thiết kế dữ liệu, css tạo 1 ứng dụng chat giống với google chat.

Tham khảo:

https://github.com/ryanb/private_pub

http://railscasts.com/episodes/316-private-pub?view=asciicast

All Rights Reserved