Rails 5+ ActionCableで作る！ シンプルなチャットアプリ コードのみ　コピペ用

# 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を変更しましょう。

```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 %>
```