Подготовка
Прежде всего добавим в Gemfile actioncable и puma:
gem 'actioncable', github: 'rails/actioncable'
gem 'puma'
ActionCable будет запускаться отдельным от основного приложения процессом. Поэтому мы будем использовать многопоточный web-сервер Puma.
Архитекутра чата
На главной странице пользователь будет вводить свой ник, после чего мы запишем его в куки и средиректим на страницу чата.
Добавим пару роутов в config/routes.rb:
resources :messages, only: [:index, :create]
resources :sessions, only: [:new, :create]
Создадим контроллеры с экшенами. Запись ника в куки:
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
cookies.signed[:username] = params[:session][:username]
redirect_to messages_path
end
end
Формы авторизации пользователя app/views/sessions/new.html.slim:
= form_for :session, url: sessions_path do |f|
p
= f.label :username, 'Введите Ваш ник'
p
= f.text_field :username
p
= f.submit 'Ок'
В самом чате пока просто будем отправлять 200 в ответ на напечатанное сообщение:
# app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def create
head :ok
end
end
Представление app/views/messages/index.html.slim:
p
= cookies.signed[:username]
p
#messages
p
= form_for :message, url: messages_path, remote: true, id: 'messages-form' do |f|
p
= f.label :body, 'Введите сообщение:'
p
= f.text_field :body
p
= f.submit 'Отправить'
Сообщение будет отправляться AJAX'ом на сервер.
Настройка ActionCalbe
Создадим три класса, которые будут ответственны за интеграцию с ActionCable.
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
# app/channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
# app/channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
def subscribed
stream_from 'messages'
end
end
Не забудьте добавить созданные директории в autoload_paths. Теперь, все, кто подписан на канал MessagesChannel, смогут получать сообщения по соответствующему потоку, определённому в методе subscribed, т.е. — messages.
ActionCable обеспечивает обмен сообщениями через Redis. Будем считать, что он у Вас уже установлен. Нам понадобиться настроить связь с ним в config/redis/cable.yml:
development: &dev
:url: redis://localhost:6379
:host: localhost
:port: 6379
:timeout: 1
:inline: true
test: *dev
production: *dev
Теперь настроим Puma:
# cable/config.ru
require ::File.expand_path('../../config/environment', __FILE__)
Rails.application.eager_load!
require 'action_cable/process/logging'
run ActionCable.server
Запускать пуму будем на порту 34523, почему бы и нет…
# /bin/bash
bundle exec puma -p 34523 cable/config.ru
Теперь пума запускается коммандой ./bin/cable.
Отправка сообщений в общий чат
Немного подправим app/controllers/messages_controller.rb:
class MessagesController < ApplicationController
def create
ActionCable.server.broadcast 'messages',
message: params[:message][:body],
username: cookies.signed[:username]
head :ok
end
end
Самое важное — подписка на канал. Создадим два coffee файла (не забудьте прореквайрить их):
#app/assets/javascripts/channels/messages.coffee
App.messages = App.cable.subscriptions.create 'MessagesChannel',
received: (data) ->
$('#messages').append("<p><b>[#{data.username}]:</b> #{data.message}</p>")
#app/assets/javascripts/channels/index.coffee
#= require cable
#= require_self
#= require_tree .
@App = {}
App.cable = Cable.createConsumer('ws://127.0.0.1:34523')
Вот и всё.
Как всегда, небольшой проект — https://github.com/lon10/live-chat
Комментарии (9)
crackedmind
12.08.2015 15:30Папку channels не нужно подключать самому, она подключается автоматом
github.com/rails/actioncable/blob/1310e580644f458069161b5b7df6c8c0f7812f7f/lib/action_cable/server/configuration.rb#L18 и далее
merc
13.08.2015 14:01-1Мне кажется, что ActionCable надо делать абстракцией над Pusher, PubNub или Centrifuge. Коннекшены должны держать спецсервервисы, а не руби.
Как киллер фича Rails 5 — не подходит.crackedmind
13.08.2015 16:54это и так абстракция над faye-websocket (которая есть и для руби, и для ноды), так что все хорошо. Self hosting никто не отменял.
merc
13.08.2015 17:01я больше доверяю самописному Pusher на Elixir, чем faye на ruby или (омг) nodejs.
Так что все скорее плохо, чем хорошо. Хотя если подключить другие сервисы легко — тогда это вовсе не проблема.crackedmind
13.08.2015 19:41ну если вы не доверяете лучшей open source реализации протокола, ваше дело :)
merc
14.08.2015 12:13Я предпочитаю использовать нормальные инструменты для держания коннектов (Erlang), вместо костылей на Руби. Faye — это именно костыль на руби.
Extrapolator
Интересно конечно, но я лучше подожду релиза RoR 5, там ActionCable будет включен в базовый функционал. Насколько я знаю, ActionCable сейчас в альфа версии.
crackedmind
Больше пользователей в альфе, больше ошибок исправят, доработок внесут.