ref https://www.rails365.net/articles/websocket-zhi-actioncable-ru-men-qi
ref https://www.pluralsight.com/guides/ruby-ruby-on-rails/creating-a-chat-using-rails-action-cable
1
2
3
4
5
6
7
#application.rb
module Default
class Application < Rails :: Application
config . action_cable . disable_request_forgery_protection = true
# config.action_cable.allowed_request_origins = ['http://192.168.0.200]
end
end
1
2
#config/routes.rb
mount ActionCable . server => '/cable'
rails g model message content:text name:string
rake db:migrate
rails g controller chats
1
2
3
4
#app/controllers/chats_controller.rb
def index
@messages = Message . all
end
1
2
3
4
5
6
7
8
9
#app/views/rooms/index.erb
< div id = "messages" class = "messages" >
< %= render @messages %>
</div>
<form id= "chat-from" >
< label > Say : < /label>
<input type="text" data-behavior="chat_speaker">
</ form >
1
2
#app/views/messages/_message.erb
<front id='message'><b> <%= message . name %> </b> : <font id="content"> <%= message . content %> </font></font>
rails g channel chat speak
1
2
3
4
5
6
#app/assets/javascripts/cable.coffee
// = require action_cable
// = require_self
// = require_tree . /channels
@App ||= {}
App . cable = ActionCable . createConsumer ()
1
2
#app/views/layouts/application.html.erb
<%= action_cable_meta_tag %>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable :: Connection :: Base
identified_by :current_user
def connect
self . current_user = find_verified_user
logger . add_tags 'ActionCable' , current_user . email
end
protected
def find_verified_user # this checks whether a user is authenticated with devise
if verified_user = env [ 'warden' ]. user
verified_user
else
reject_unauthorized_connection
end
end
end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#app/channels/chat_channel.rb
class ChatChannel < ApplicationCable :: Channel
def subscribed
stream_from "chat_channel"
end
def unsubscribed
end
def speak ( data )
if not data [ 'message' ] == ""
Message . create! content : data [ 'message' ] , name : current_user . name
end
end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#app/assets/javascripts/channels/chat.coffee
App . chat = App . cable . subscriptions . create "ChatChannel" ,
connected : ->
$ ( '#messages' ) . scrollTop ( $ ( '#messages' ) [ 0 ]. scrollHeight )
disconnected : ->
received : ( data ) ->
$ ( '#messages' ) . append ( data [ 'message' ] )
$ ( '#messages' ) . scrollTop ( $ ( '#messages' ) [ 0 ]. scrollHeight )
speak : ( message ) ->
@perform 'speak' , message : message
$ ( document ) . on 'keypress' , '[data-behavior~=chat_speaker]' , ( event ) ->
if event . keyCode is 13
App . chat . speak event . target . value
event . target . value = ""
event . preventDefault ()
rails g job MessageBroadcast
1
2
3
4
5
6
7
8
9
10
11
12
13
#app/jobs/message_broadcast_job.rb
class MessageBroadcastJob < ApplicationJob
queue_as :default
def perform ( message )
ActionCable . server . broadcast 'chat_channel' , message : render_message ( message )
end
private
def render_message ( message )
ApplicationController . renderer . render ( partial : 'messages/message' , locals : { message : message })
end
end
1
2
3
4
#app/models/message.rb
class Message < ApplicationRecord
after_create_commit { MessageBroadcastJob . perform_later self }
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#scss
#messages {
overflow : auto ;
position : relative ;
margin-left : 15 px ;
height : 75 vh ;
width : 90 % ;
margin-bottom : 2 vh ;
}
#message {
margin-left : 10 % ;
font-size : 25 px ;
line-height : 27 px ;
position : relative ;
}
#content {
color : grey ;
font-size : 25 px ;
line-height : 27 px ;
}
#chat-from {
margin-left : 10 % ;
margin-bottom : 20 px ;
position : relative ;
}