Dựng trang web chat đơn giản với rails 5.0.0 beta bằng Action Cable
Nhưng mình đã hứa ở bài viết link là ở rails 5 bạn đã có thể tự viết 1 ứng dụng web chat đơn giản ngay trên rails mà không cần phải cài đặt thêm 1 gem gì bên ngoài hỗ trợ thông qua tính năng mới trên bản rails 5.0.0 này đó là Action Cable.Để hiểu rõ hơn về Action Cable và cập nhật rails 5 bạn có ...
Nhưng mình đã hứa ở bài viết link là ở rails 5 bạn đã có thể tự viết 1 ứng dụng web chat đơn giản ngay trên rails mà không cần phải cài đặt thêm 1 gem gì bên ngoài hỗ trợ thông qua tính năng mới trên bản rails 5.0.0 này đó là Action Cable.Để hiểu rõ hơn về Action Cable và cập nhật rails 5 bạn có thể đọc qua ở bài viết này. Nếu bạn đã đọc xong hoặc chỉ muốn start app ngay thì chúng ta hãy bắt đầu thôi. Đầu tiên bạn phải nâng cấp bản rails lên bản 5.0.0(khuyến cáo nên cập nhật luôn phiên bản ruby của bạn vì rails 5 chỉ làm việc với phiên bản ruby >= 2.2.1) Bạn có thể cập nhật bằng việc viết thêm dòng vaò file Gemfile
#Gemfile gem 'rails', '>= 5.0.0.beta3'
Sau đó chạy lệnh
bundle
để cài đặt rails 5.0.0.
Hoặc sử dụng lệnh
gem install rails -v 5.0.0.beta1
tiếp theo ta sẽ tạo 1 project chat đơn giản
rails new chat --skip-spring #tạo project chat cd chat #chuyển thư mục vào app vừa tạo rails g controller chat index #khởi tạo controller chat với action index rails g model message content:text, user_name:string #khởi tạo CSDL bảng message với trường content và user_name rails db:migrate #khởi tạo CSDL #bạn có thể thấy ta đã có thể dùng lệnh rails db:migrate thay cho rake db:migrate ở phiên bản rails 5 này, và tất cả các lệnh rake khác
Tiếp tục ở controller room ta viết như sau
# app/controllers/rooms_controller.rb class ChatsController < ApplicationController def index @messages = Message.all #load tất cả các message end end
tiếp theo ta cần tạo view cho app chat
# app/views/chats/index.html.erb <h1>Chat room</h1> <div id="messages"> <%= render @messages %> </div> <form> <label>Say something:</label><br> <input type="text" data-behavior="room_speaker"> </form>
# app/view/chats/_message.html.erb <div class=“message”> <p><%= message.user_name + ": "+ message.content %></p> </div>
OK, như vậy đã xong phần view hiện thị. Giờ sẽ tới phần việc chính đó là tạo kênh (channel) chat cho room
rails g channel room speak
tiếp theo ta cần config cho kênh vừa được khởi tạo
# app/channels/room_channel.rb class RoomChannel < ApplicationCable::Channel def subscribed stream_from "room_channel" end def unsubscribed # các lệnh mà bạn muốn chạy khi người dùng out ra khỏi kênh end def speak(data) # ActionCable.server.broadcast "room_channel", message: data['message'] Message.create! user_name: data['user_name'], content: data['message'] end end
Để bật chức năng Action Cable chúng ta cần thêm vào file config/routes.rb như sau
# config/routes.rb mount ActionCable.server => '/cable'
Tiếp theo ta cần bật js cho cable bằng việc bỏ comment cho 2 dòng sau ở file app/assets/javascripts/cable.coffee
#app/assets/javascripts/cable.coffee @App ||= {} App.cable = ActionCable.createConsumer()
kế đến ta cần tạo file js để xử lý việc hiện text trong room chat
# app/assets/javascripts/channels/room.coffee App.room = App.cable.subscriptions.create "RoomChannel", connected: -> # sau khi đã kết nối được với kênh RoomChannel disconnected: -> # sau khi kết thúc kết nối với kênh RoomChannel received: (data) -> $('#messages').append data['message'] # khi nhận được data từ kênh chat, dòng lệnh trên sẽ in đoạn chat mới nhận được lên màn hình # data['message'] ở đây đã bao gồm cả đoạn html lấy từ file view/mesages/_message.html.erb được render ra từ phần ** speak: (message) -> @perform 'speak', message: message #thông báo tới các kênh lắng nghe rằng có nội dung mới với thông tin user_name và message $(document).on 'keypress', '[data-behavior~=room_speaker]', (event) -> if event.keyCode is 13 # return = send App.room.speak event.target.value, event.target.value = "" #khởi tạo lại giá trị event.preventDefault()
Tiếp tục ta cần xác định thời điểm thông báo nội dung chat tới các client lắng nghe đó là lúc sau khi message được tạo ra
# app/models/message.rb class Message < ApplicationRecord after_create_commit { MessageBroadcastJob.perform_later self } end
Cuối cùng ta cần khai báo MessageBroadcastJob mà gọi ở trên
trên terminal ta chạy lệnh
rails g job MessageBroadcast
Lệnh trên sẽ sinh ra file message_broad_cast.rb trong folder job, ta cần định nghĩ hàm perform cho class mới này như sau:
class MessageBroadcastJob < ApplicationJob queue_as :default def perform(message) ActionCable.server.broadcast 'room_channel', message: render_message(message) #gọi đến action cable để thông báo nội dung message mới đc tạo ra end private def render_message(message) ApplicationController.renderer.render(partial: 'chats/message', locals: { message: message }) # ** # trả ra nội dung html cho đoạn message để đoạn code js in ra màn hình end end
OK đã xong bây giờ bạn có thể bật trang server local bằng lệnh rails s và vào đường link http://localhost:3000/chats trên nhiều trình duyệt để chat với nhau
Hoặc nếu bạn muốn chat qua mạng nội bộ thì có thể thay http://dia_chi_ip_may_ban:3000/chats
note: nhớ đường dẫn cho controller chat trong file router.rb nhé
#config/routes.rb resources :chats, only: :index
Extra: Một số hàm mới cập nhật active record trên rails 5 mà ta nên biết
Thêm nhiều hàm mới cho Time & Date
- on_weekend?
trả giá trị true nếu Date/Time vào thứ 7 hoặc chủ nhật
Time.current => Fri, 12 Feb 2016 09:47:40 UTC +00:00 Time.current.on_weekend? => false Time.current.tomorrow => Sat, 13 Feb 2016 09:48:47 UTC +00:00 Time.current.tomorrow.on_weekend? => true
tương tự với hàm
- on_weekday?
trả giá trị true nếu Date/Time vào các ngày trừ 7/chủ nhật
- pluck hàm pluck có thay đổi lớn đó là nó được dùng cho Enumerable objects ví dụ:
users = [{id: 1, name: 'Max'}, {id: 2, name: 'Mark'}, {id: 3, name: 'George'}] users.pluck(:name) => ["Max", "Mark", "George"] # Takes multiple arguments as well users.pluck(:id, :name) => [[1, "Max"], [2, "Mark"], [3, "George"]]
do thay đổi đó mà việc dùng pluck với active record có sự thay đổi, bạn có thể thấy qua ví dụ:
# With Rails 4.x users = User.all SELECT `users`.* FROM `users` users.pluck(:id, :name) SELECT "users"."id", "users"."name" FROM "users" => [[2, "Max"], [3, "Mark"], [4, "George"]] # With Rails 5 users = User.all SELECT "users".* FROM "users" # does not fire any query users.pluck(:id, :name) => [[1, "Max"], [2, "Mark"], [3, "George"]]
bạn có thể thấy sự khác nhau ở câu lệnh query vì ở rails 5 pluck đã không còn được dùng để sinh ra câu lệnh truy vấn mà chỉ dùng để xử lý dữ liệu trả về, vì vậy khi dùng bạn nên chú ý, nếu bạn chỉ muốn lấy 1 vài trường thì select sẽ đảm bảo cho câu query của bạn chạy nhanh hơn.
Ngoài ra bạn có thể xem ở đây để biết thêm nhiều hàm mới khác được áp dụng ở rails 5 mới này
Đặc biệt ở rails 5 bạn đã có thể dùng lệnh or mà không phải viết riêng thành câu truy vấn
# để lấy các Post có id = 1 hoặc 2 Post.where('id = 1').or(Post.where('id = 2'))
bạn có thể kết hợp cho nhiều kiểu điều kiện khác nhau như:
(A && B) || C: Post.where(a).where(b).or(Post.where(c)) (A || B) && C: Post.where(a).or(Post.where(b)).where(c)
tham khảo:
- http://hectorperezarenas.com/2015/12/26/rails-5-tutorial-how-to-create-a-chat-with-action-cable/
- http://juanitofatas.com/2015/01/31/rails-5-active-record-or/