ActionCableでセッションを使う

(追記)ちょっと自信なくなってきた(スタンドアロン版だとちょっと違うのでは?という気がしてきた)ので今度時間のあるときに調べます

Rails Guidesを読むと、Action Cableはセッション使えないと書いてあるのだけど、よくよく考えるとAction Cable はRailsのルーティングにマウントして使う形式だし、そうするとセッション用のRack Middlewareは使われているはずでなんかおかしいぞ…?と思って調べたら普通に

request.session[:user_id]

みたいな感じでセッション情報を取得できた。Rails Guidesはおそらくクッキーセッションを利用して別ドメインでAction Cableのサーバを立ててる前提で書かれてるんじゃないかという気がする。仮に別ドメインでも

  • redisなどのセッションストアを使う
  • Action Cableのサーバをサブドメインにして、セッションクッキーをサブドメインと共有にする

などすれば普通に使えそう(未検証)。

Action Cable Overview — Ruby on Rails Guides

webpacker3のコードをざっと読んだ

webpacker3は、「2から導入されたテスト環境でのlazy compileが開発環境にも入り、webpack-dev-serverの起動が必須ではなくなった」「デフォルト設定類がnpmのパッケージ側に寄せられた」くらいの認識だったのだけど、コード見るとどうやらそれ以外の変更も入っているみたいですね。

  • 開発環境だとWebpacker::DevServerProxyがミドルウェアの先頭に入る
  • Webpacker::DevServerProxyはRack::Proxyを継承している。やっていることは
    • /assets/packs(デフォルトの場合)配下にリクエストが来ている、かつwebpack-dev-serverが起動していたらwebpack-dev-serverにプロキシする
  • 「webpack-dev-serverが起動している」というのは設定しているホスト&ポートに対してTCPソケットで接続を試してつながれば起動しているとみなす
    • webpacker 3.0.1まではここの例外処理に問題があって、例えばdocker-compose環境などを使用しているとErrno::EADDRNOTAVAILなどで死んだりしていた
      • 3.0.2で解消されたはず

webpacker2までは、webpack用のassetsはアプリケーションサーバとは別のwebpack-dev-serverのアドレスに対してリクエストしていたのだけど、webpacker3ではそれがなくなってアプリケーションサーバ内でうまいことしてくれるようになったのだった。

余談

webpackerをアップグレードしたときはyarn upgrade @rails/webpackerも一緒に実行してgemとバージョンを合わせて置いたほうが良さそう(忘れると死にそう)。

headless chromeをdockerで動かすときに注意する点

前提

  • Google Chrome 61.0.3163.100
  • chromedriver 2.3.1
  • Docker 17.03.1-ce
  • docker-compose 1.11.2

注意点

  • dockerがデフォルトで利用しているseccompの設定だとheadless chromeが動かない
  • seccompを変更することはできる

    • dockerコマンドのオプションでseccomp用の設定ファイルを渡すことができる
    • chromeを動かすための設定ファイルを作って公開している人がいる
  • しかし現行のdocker-composeだと、設定ファイルを渡すやり方ができない

    • docker-compose.ymlに一つづつ設定を書いていくことはできるがダルい
    • seccomp:unconfinedのようにしてseccomp自体を無効にすることはできるがセキュリティ的に不安
    • 次のようにCAP_SYS_ADMINを設定することで、↑よりはだいぶマシな感じになる
services:
  app:
    # ...
    cap_add:
      - sys_admin

参考

webpacker2から3へアップグレード

だいたい次のような感じで行けるはず(実際は試行錯誤したのでこの通りにはやっていない)。設定ファイルやpackage.jsonに記載されるpackageなどがだいぶ減った。

  • bundle update webpacker
  • config/webpack 配下を全部消す
  • package.jsonを消す
  • yarn.lockを消す
  • public/packs配下にファイルが有れば消す
  • ./bin/rails webpacker:install
  • ./bin/webpacker などをオーバライドする
  • 差分を見て残すべきものを残す

package.jsonに無駄な指定が残っているのに気付かず、webpackerのバージョン違いが2つ混在する形になっていてしばらく時間吸われた。

それほどjsを使っているわけではないアプリケーションなのでバージョン上げても大差ないのだけど、webpack-dev-serverがなくても大丈夫になったのは大きい。

Redashをherokuでホスティングする

モチベーション

  • Redashを楽に安くホスティングしたい
  • 以前はherokuでのホスティングをサポートしていたけど、現在はサポートなし
  • しかしDockerでのホスティングをサポートしているようなので、DockerイメージをherokuにpushしてしまえばherokuでもRedash使えるのではないかと考えた

いくつか気をつけるべき点があったけど、比較的すんなりRedashをherokuで動かすところまで行けたので要点をまとめる

気をつけるべき点

herokuでDockerコンテナ動かすにあたっていくつか気をつける点があった。

  • WORKDIRのデフォルトが/なので/appに変更する
  • $PORTをポート番号として受け付ける必要がある
    • 公式のDockerイメージで使うサーバ起動コマンドは5000番ポートが決め打ちで書かれていて、さらに外から変更することができなかった
    • ↑を解決するためにENTRYPOINTの部分だけ削除したDockerfileからイメージを作ってDockerHubに置いてそれを使うようにした

あとはアドオンの問題。HerokuRedisの無料プランを使うと20接続までしか受け付けず、コネクションエラーになる。RedisCloudだと無料で30コネクションまで使えてうまく動く。

できあがったDockerfileは↓で管理しているのでherokuでRedash使ってみたい方は参考にしてみてください。

willnet/redash-on-heroku: Dockerfiles for hosting redash on heroku

感想

herokuでDockerコンテナ動かすの、思ってたよりかなり楽だった。herokuすごい

puma-devとwebpackerを使ってHTTPSで開発する

OneSignalを利用してブラウザPush通知機能を追加した際に、HTTPSでのみ使用する前提のJSライブラリを入れたのが原因で、開発環境でもHTTPSを利用する必要が出た。

前提として、

  • Mac OSX
  • puma-dev
  • webpacker

を利用している。puma-devはHTTPSに対応していて、自動でオレオレ証明書を作ってくれる。

webpack-dev-serverもHTTPSに対応している。次のようにconfig/webpacker.ymlのhttpsをtrueにするとhttps://example.com:8080/packs/application.jsといったURLでwebpackがコンパイルしたjsにアクセスできる。

development:
  <<: *default

  dev_server:
    host: example.com
    port: 8080
    https: true

問題はオレオレ証明書の認証。chromeであれば毎回https://example.com:8080/packs/application.js直接アクセスして認証する必要がある。認証しないとJS読み込みでエラーになる。毎回やるのは大変面倒*1

chromeでwebpack-dev-serverが生成した証明書を見ると「Subject Alt Nameが設定されていない」というエラーが出ていて、これにも対応する必要がありそう。puma-devはこのエラーは出ていなかった。

解決方法

次のコマンドで証明書を生成する

openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout server.pem \
    -new \
    -out server.pem \
    -subj /CN=savanna.dev \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /System/Library/OpenSSL/openssl.cnf \
        <(printf '[SAN]\nsubjectAltName=DNS:savanna.dev')) \
    -sha256 \
    -days 3650

config/webpack/server.pem など適当な場所に置く。

キーチェーンへこの証明書を登録し、「常に信頼」の設定にする。

次のようにしてwebpack-dev-serverを起動する

./bin/webpack-dev-server --cert ./config/webpack/server.pem --key ./config/webpack/server.pem

オプションを毎回つけるのがダルいのであればconfig/webpack/development.jsを次のようにしておく

const fs = require('fs');
// 省略
devServer: {
  clientLogLevel: 'none',
  https: {
    cert: fs.readFileSync('./config/webpack/server.pem'),
    key: fs.readFileSync('./config/webpack/server.pem'),
  },
  // 省略  

余談

ドメインがlocalhostでよければ chrome://flags/#allow-insecure-localhost を有効にすれば大丈夫そう(未確認)。

参考

*1:とりあえずの回避策として該当のJSライブラリを開発環境で読み込まないようにしようかとも思ったけど、バグの温床になりそうなのでやめた

jquery-ujsからrails-ujsへの移行で気をつけること

  • jquery-ujs だと data, status, xhr
  • rails-ujs だと event だけ
    • レスポンスの情報がほしいときは event.detailの中をみる
document.body.addEventListener('ajax:success', function(event) {
  var detail = event.detail;
  var data = detail[0], status = detail[1],  xhr = detail[2];
})

参考

jquery-ujs/rails.js at master · rails/jquery-ujs rails/ajax.coffee at 896ee2b679462e7bcaa6890c6f5fdbd3b2e2fccb · rails/rails rails/remote.coffee at 896ee2b679462e7bcaa6890c6f5fdbd3b2e2fccb · rails/rails rails/event.coffee at 896ee2b679462e7bcaa6890c6f5fdbd3b2e2fccb · rails/rails Working with JavaScript in Rails — Ruby on Rails Guides