Ruby on Rails5の新機能ActionCableを試す!

※1 執筆時のRailsはバージョン5.0.0.1。
※2 Webサーバにはnginxを使用。
※3 リバースプロキシにnginxを使った構成も対応する。

Rails5.0.0.1はすでにインストールされているものとする。

定番のコマンドでプロジェクトを作る。

$ rails new sample-project

次にチャンネルを作る。
これにより作成されるファイルは下記の通り。
<hoge_channel.rb>はサーバサイドが行う処理が記述される。
<hoge.coffee>はクライアントサイドが行う処理が記述される。

$ rails g channel hoge piyo
(hogeがチャンネル名、piyoはアクション名)
      create  app/channels/hoge_channel.rb
   identical  app/assets/javascripts/cable.js
      create  app/assets/javascripts/channels/hoge.coffee

※ もしエラーが出たらGemfileのtherubyracerがコメントアウトされていると思うので有効にしてbundle installする。

<development.rb, production.rb>に「ソケットを許可するアクセス元」を追記。
つまり自分のドメインを書けば良い。

config.action_cable.allowed_request_origins = ['http://hogepiyo.com']

Railsの準備は以上。
次はnginxサーバの設定に移る。

!注意点!

rc版のRailsでは<route.rb>に

mount ActionCable.server => '/cable'

を書いたり、

<cable.coffee>の

@App ||= {}
App.cable = ActionCable.createConsumer()

をコメント外したりという作業が必要だった。
Ruby on Rails 5.0.0.1ではこれら作業は必要ない。

ここからNginxの設定。
RailsではWebSocketを使うのにPuma等が推奨されている。
Unicornはあいにく非推奨、これはシングルスレッドノンブロッキングI/Oという仕様のため。
そのためPumaに対してPIDないしSocketでアクセスを流してあげるのが好ましい(たぶん)
設定内容は単純に/cable(RailsのWebSocketの標準設定)へのアクセスをupgradeしてPumaに渡すだけである。

Nginxのconfファイルの参考

upstream puma {
  server unix:/var/run/puma.sock fail_timeout=0;
}

server {
中略
    location /cable {
        proxy_pass http://puma/cable;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
中略
}

これで晴れてActionCable(WebSocket)機能が動くようになる。

また、nginxのリバースプロキシがある場合は、リバースプロキシにも設定が必要になる。
アプリケーションサーバと同様に/cableに対して
upgradeしてアプリケーションサーバへアクセスを流すだけである。

server {
中略
    location /cable {
           proxy_pass http://backend;
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
           proxy_set_header Host $host;
    }
中略
}

もしこの記述をしなかった場合サーバは404を返すうえに、
アプリケーションサーバではこのようなエラーログが残る。

ブラウザのコンソールに表示されるログ
WebSocket connection to 'ws://hogepiyo.com/cable' failed: Error during WebSocket handshake: Unexpected response code: 404

Railsのログにはこのように出力される
Started GET "/cable" for *.*.*.* at YYYY-MM-DD 00:00:00 +0900
Started GET "/cable/"[non-WebSocket] for *.*.*.* at YYYY-MM-DD 00:00:00 +0900
Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )
Finished "/cable/"[non-WebSocket] for *.*.*.* at YYYY-MM-DD 00:00:00  +0900
※ IP等は伏せてる

ここで注意しないといけないのがこの一行を忘れないこと。
> proxy_set_header Host $host;

[Ruby on Rails] DBのcollation設定

Railsでutf8_general_ciなど任意のcollationを使いたい。

Before:

default: &default
adapter: mysql2
encoding: utf8
pool: 5
username: hoge
password: piyo
host: localhost

After:

default: &default
adapter: mysql2
encoding: utf8
charset: utf8
collation: utf8_general_ci
pool: 5
username: hoge
password: piyo
host: localhost

[Ruby] [Ruby on Rails] PassengerのApache2 moduleインストール時のエラー

※ この記事はApache2をソースからインストールした場合を対象とする。

Apache2でRuby on Railsを使うなら
Passengerをインストールすることになる。

普通にインストール作業を進めていくと
Apache2用モジュールのインストールウィザードで
ちょっとしたエラーが発生する。

それがこちらドン。

$ sudo gem install passenger
$ sudo passenger-install-apache2-module
中略
Checking for required software...

 * Checking for C compiler...
      Found: yes
      Location: /usr/bin/cc
 * Checking for C++ compiler...
      Found: yes
      Location: /usr/bin/c++
 * Checking for Curl development headers with SSL support...
      Found: yes
      Error: Cannot find the `curl-config` command.
 * Checking for OpenSSL development headers...
      Found: yes
      Location: true
 * Checking for Zlib development headers...
      Found: yes
      Location: true
 * Checking for Apache 2...
      Found: no
 * Checking for Apache 2 development headers...
      Found: no
 * Checking for Rake (associated with /usr/local/bin/ruby)...
      Found: yes
      Location: /usr/local/bin/ruby /usr/local/bin/rake
 * Checking for OpenSSL support for Ruby...
      Found: yes
 * Checking for RubyGems...
      Found: yes
 * Checking for Ruby development headers...
      Found: yes
      Location: /usr/local/include/ruby-2.1.0/ruby.h
 * Checking for rack...
      Found: yes
 * Checking for Apache Portable Runtime (APR) development headers...
      Found: no
 * Checking for Apache Portable Runtime Utility (APU) development headers...
      Found: no

Apache2のあたりでnoと言われて停止してしまった。
これはシェルの環境変数でApache2のインストールディレクトリへ
パスを通しておけばいいんだけど、
sudoでコマンドを実行すると結局同じエラーが出てしまう。

それなら最初からrootで作業すると手っ取り早い。

$ sudo su -
# export APXS2=/usr/local/apache2/bin/apxs
# export PATH=/usr/local/apache2/bin:$PATH
# passenger-install-apache2-module