rails チャットアプリ
コピペ用
リポジトリ
https://github.com/tacyan/camp
rails new camp
cd camp
rails g controller rooms show
config/routes.rb
Rails.application.routes.draw do
root to: 'rooms#show'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
# Serve websocket cable requests in-process
# mount ActionCable.server => '/cable'
end
$ rails g model message content:text
$ rails db:migrate
app/controllers/rooms_controller.rb
class RoomsController < ApplicationController
def show
@messages = Message.all
end
end
ディレクトリ作成
mkdir -p app/views/messages
app/views/messages/_message.html.erb
<div class="message">
<p><%= message.content %></p>
</div>
app/views/rooms/show.html.erb
<h1>Chat room</h1>
<div id="messages">
<%= render @messages %>
</div>
DBの作成
$ rails console
> Message.create! content: 'Hello world!'
rails g channel room speak
config/routes.rb
Rails.application.routes.draw do
# (省略)
# Serve websocket cable requests in-process
mount ActionCable.server => '/cable'
end
app/assets/javascripts/channels/room.coffee
App.room = App.cable.subscriptions.create "RoomChannel",
# (省略)
speak: (message) ->
@perform 'speak', message: message
app/channels/room_channel.rb
class RoomChannel < ApplicationCable::Channel
def subscribed
stream_from "room_channel"
end
# (省略)
def speak(data)
ActionCable.server.broadcast 'room_channel', message: data['message']
end
end
app/assets/javascripts/channels/room.coffee
App.room = App.cable.subscriptions.create "RoomChannel",
# (省略)
received: (data) ->
alert data['message']
# (省略)
ブラウザのJavaScriptコンソールから
App.room.speak('Hello world')
とするとアラートが出力します。
app/views/rooms/show.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/assets/javascripts/channels/room.coffee
$(document).on 'keypress', '[data-behavior~=room_speaker]', (event) ->
if event.keyCode is 13 # return = send
App.room.speak event.target.value
event.target.value = ''
event.preventDefault()
ここまでは正常に来ましたが、現在はjqueryが入っていない為、
相互通信が出来ません。
Gemfileを変更しましょう。
# add jquery
gem 'jquery-rails'
gem 'jquery-turbolinks'
bundle install
bundle install
$ bundle install|grep jquery
Using jquery-rails 4.3.1
Using jquery-turbolinks 2.1.0
app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require jquery.turbolinks
ここで、Say somethingを叩くと、alertが出力されます。
次にDBに保存しましょう。
app/channels/room_channel.rb
# (省略)
def speak(data)
Message.create! content: data['message']
end
app/models/message.rb
class Message < ApplicationRecord
after_create_commit { MessageBroadcastJob.perform_later self }
end
続いて、非同期でブロードキャストするためのMessageBroadcastジョブを作成します。
rails g job MessageBroadcast
app/jobs/message_broadcast_job.rb
class MessageBroadcastJob < ApplicationJob
queue_as :default
def perform(message)
ActionCable.server.broadcast 'room_channel', message: render_message(message)
end
private
def render_message(message)
ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message })
end
end
app/assets/javascripts/channels/room.coffee
App.room = App.cable.subscriptions.create "RoomChannel",
# (省略)
received: (data) ->
$('#messages').append data['message']
# (省略)
app/views/messages/_message.html.erb
<% cache message do %>
<div class="message">
<p><%= message.content %></p>
</div>
<% end %>