Action Cableでユーザーのコミュニケーションを活性化する

#Action Cacleの基礎情報　
## Action Cableとは
Railsと同じような記述の仕方で、即時更新機能を実装できるフレームワーク。実装内容としては、メッセージの保存や送信に必要なRubyのコーディングと、保存したメッセージを即時に表示させるJavaScriptのコーディングです。

## チャネル
即時更新機能を実装するサーバー側の仕組みのこと。データの経路を設定したり、送られてきたデータをクライアント画面上に表示させたりする。

##チャネルを作成する
```
% rails g channel message
```
生成される、app/channels/message_channel.rbとapp/javascript/channels/message_channel.jsが重要なファイルです。

```
・ message_channel.rbの役割
このファイルは、クライアントとサーバーを結びつけるためのファイルです。
・ message_channel.jsの役割
このファイルは、サーバーから送られてきたデータをクライアントの画面に描画するためのファイルです。
```
##stream_from
stream_fromとは、サーバーとクライアントを関連付けるメソッドです。Action Cableにあらかじめ用意されています。

```
app/channels/message_channel.rb

class MessageChannel < ApplicationCable::Channel
  def subscribed
    stream_from "message_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end
```
##broadcast（ブロードキャスト）
broadcastとは、サーバーから送られるデータの経路のことを指します。
broadcastを介してデータをクライアントに送信します。メッセージの保存が成功したときに、broadcastを介してメッセージが送信されるように記述します。

```
app/controller/messages_controller.rb

class MessagesController < ApplicationController
  def new
    @messages = Message.all
    @message = Message.new
  end

  def create
    @message = Message.new(text: params[:message][:text])
    if @message.save
      ActionCable.server.broadcast 'message_channel', content: @message
    end
  end
end
```
broadcastを通して、'message_channel'に向けて@messageを送信するということです。
受け取った情報は、receivedの引数dataに入ります。

##ActionCableを本番環境で使用するための設定
以下を順番に説明します。
1.HerokuでもAWSでも必要な設定
2.Herokuを用いてデプロイする場合にのみ必要な設定
3.AWSを用いてデプロイする場合にのみ必要な設定

##1.HerokuでもAWSでも必要な設定
###cable.yml
cable.ymlとはActionCableを使用する際の設定を記述するファイルです。
ここでは、本番環境の仕様設定に編集を加えます。
具体的には、使用する adapter の指定を変更します。
###adapter
ActionCableは、サーバーから送信された情報をクライアントへ提供する仕組みがあって成り立っています。
その仕組みと連携するためのものをadapterと言います。
使用できるadapterの種類には、以下表の3通りがあります。

```
Asyncアダプタ : 一方で、パフォーマンスの面から本番環境での利用は非推奨（個人アプリの規模であれば、基本的に挙動に問題はない）。
Redisアダプタ : 本番環境での利用が推奨されている。一方で、EC2を用いたデプロイを行う際に、幾らか料金がかかる（設定にもよるが、12ヶ月のAWS無料期間超過後からは、EC2料金とは別に約2000円〜/月）。
PostgreSQLアダプタ : 本番環境での利用が推奨されている。一方で、データベースとのやりとりには、PostgreSQLを使用していることが条件。
```

##
```
config/cable.yml

development:
  adapter: async
test:
  adapter: test
production:
  adapter: async # 追記
  # adapter: redis 削除
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: mini_talk_app_production
```
#2.Herokuを用いてデプロイする場合にのみ必要な設定
本番環境の設定ファイルである、config/environments/production.rbを編集します。
ActionCableは、指定されていないオリジンからのリクエストを受け付けない設定がなされています。
設定を編集し、本番環境でActionCableを使用できるようにしましょう。

```
config/environments/production.rb

Rails.application.configure do # このブロックの中であればどこに記載しても良い

# 省略

  ActionCable.server.config.disable_request_forgery_protection = true
  config.action_cable.url = "wss://【Herokuアプリ名】.herokuapp.com/cable" 
  config.action_cable.allowed_request_origins = ['https://【Herokuアプリ名】.herokuapp.com', 'http://【Herokuアプリ名】.herokuapp.com']

# 省略

end
```
ここまでで、Herokuを用いてデプロイする場合の設定は完了です。

Herokuへデプロイする場合には、commit と pushを行い、git push heroku masterコマンドにてデプロイを行いましょう。
#3.AWSを用いてデプロイする場合にのみ必要な設定
本番環境の設定ファイルである、config/environments/production.rbを編集します。
ActionCableは、指定されていないオリジンからのリクエストを受け付けない設定がなされています。
設定を編集し、本番環境でActionCableを使用できるようにしましょう。

```
config/environments/production.rb

Rails.application.configure do # このブロックの中であればどこに記載しても良い

# 省略

  ActionCable.server.config.disable_request_forgery_protection = true
  config.action_cable.url = "ws://【Elastic IP】/cable" 
  config.action_cable.allowed_request_origins = ['http://【Elastic IP】']

# 省略

end
```

WebサーバーとしてNginxを用意した場合。
ActionCableを用いる場合、サーバーサイドへのリクエストを受け取る役目のあるWebサーバーにて、websocketの仕組みを用いるための設定をする必要があります。

以下のコマンドで、rails.confを開きます。

```
ターミナル(EC2内で実行)

sudo vim /etc/nginx/conf.d/rails.conf
```
開けたら、下記のコードを追記しましょう。

```
/etc/nginx/conf.d/rails.conf

upstream app_server {
  server unix:/var/www/アプリケーション名/shared/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name Elastic IP;

  root /var/www/アプリケーション名/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    root   /var/www/アプリケーション名/current/public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }
# -------------------ここから-------------------
# /cableのパスに対してwebsocketの仕組みを用いるための設定
  location /cable {
    proxy_pass http://app_server/cable;
    proxy_http_version 1.1;
    proxy_set_header Upgrade websocket;
    proxy_set_header Connection Upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
# -------------------ここまでを追記-------------------
  error_page 500 502 503 504 /500.html;
}
```
保存が完了したら、以下のコマンドを入力しましょう。
Nginxの設定ファイルの読み込み直しとNginxの再起動を行います。

```
ターミナル(EC2内で実行)

# 読み込み直し
sudo systemctl reload nginx

# 再起動
sudo systemctl restart nginx
```
追記が完了したら、commit と pushを行い、bundle exec cap production deploy コマンドにてデプロイを行いましょう。

 デプロイコマンドは、ターミナル（ローカル）で実行します。
これでAWSを用いたデプロイの場合も、準備が完了しました。
最後に挙動確認を行いましょう。
本番環境にて、ローカル環境と同様の挙動が確認できれば設定完了です。