2014/12/30

mean-cliでアプリケーションのひな形を作る。

mean-cliを使ってアプリケーションのひな形を作るまでの手順を纏めてみます。

準備

NodeJS、MongoDB、Git

前提として、NodeJS、MongoDB、Gitが必要。それぞれインストールしておく。 ここでは詳細は割愛。

npmのバージョンを上げておく。

npmのバージョンが2.xでないとWARNINGが出るので、上げておく。

$ npm update -g npm
を実行する。

Grunt.jsあるいはGulp.jsをインストールしておく

meanで作成するプロジェクトは、タスクマネージャとしてGruntかGlupを選択できる。デフォルトはGrunt。両方入れておく。

$ npm install -g grunt-cli gulp

mean-cliをインストールする。

インストールするのは、mean-cli。なので、

$ npm install -g mean-cli
を実行する。

mean-cliを使ってプロジェクトを作る。

インストールしたmean-cliを使って、Webアプリケーションプロジェクトを作成する。例えば、teamというプロジェクトを作るには、

$ mean init team
を実行する。すると、アプリケーション名と利用するタスクマネージャ(GruntかGulpか、僕はGulpを選択)を問われ、答えるとプロジェクトディレクトリを生成してくれる。

npmパッケージのインストール

生成されたプロジェクトのルートに移動し、npm installを実行する。

$ cd /path/to/team
$ npm install

アプリケーションの起動

アプリケーションを起動してみる。Gulpを使うよう指示したので、gulpのデフォルトタスクを起動するとアプリケーションが起動する。

$ gulp
そして、http://localhost:3000にアクセスすると、↓のような画面が表示される。

ヘッダの「Join」リンクをつつくと、ユーザ登録ページに遷移する。

また、「Log in」リンクをつつくとログインページに遷移する。

初めてmean-cliを使って、アプリケーションのひな形を作るところまでやってみました。 これから実際に何か作ってみます。ちなみに、あのキャラクターは、Daphneっちゅー忍者らしいですね。JenkinsとかYeomanとかキャラがおっさんだったから、ちょっと可愛いなと思いました。どうでもいいですけど。

2014/11/20

PM2でnodeなWebアプリをデプロイしてみた

npmにPM2というプロセスマネージャツールがあって、プロセスの起動、終了、監視などを便利に行ってくれる。実はPM2にはアプリのデプロイもできちゃうことを知ったので試してみました。

デプロイのフロー

基本的なフローは、PM2/ADVANCED_README.md at development · Unitech/PM2に書いてあるとおりで行けましたんで、流れを纏めておこうと思います。

ecosystem

PM2でデプロイしたいアプリケーションや、デプロイ先の情報は、jsonファイルに記述します。そのファイルのひな形を作るコマンドが、

$ pm2 ecosystem
です。このコマンドを叩くと、↓のようなファイルが生成されます。こいつを自分の環境に合わせて編集します。
{
  "apps" : [{
    "name"      : "API",
    "script"    : "app.js",
    "env": {
      "COMMON_VARIABLE": "true"
    },
    "env_production" : {
      "NODE_ENV": "production"
    }
  },{
    "name"      : "WEB",
    "script"    : "web.js"
  }],
  "deploy" : {
    "production" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/production",
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env production"
    },
    "dev" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/development",
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env dev"
    }
  }
}

setup

デプロイ先にsshで接続し、アプリケーション格納ディレクトリを掘ったり何やらかんやらするコマンドが、

$ pm2 deploy ecosystem.json production setup
です。上述のecosystem.jsonを指定してdeployのsetupを行います。このままだと、デプロイ先のサーバに対して、22ポートを指定してsshで接続にいきます。sshのポート番号を指定するには、ecosystem.jsonに追記します。
{
  "apps" : [{
    "name"      : "API",
    "script"    : "app.js",
    "env": {
      "COMMON_VARIABLE": "true"
    },
    "env_production" : {
      "NODE_ENV": "production"
    }
  },{
    "name"      : "WEB",
    "script"    : "web.js"
  }],
  "deploy" : {
    "production" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/production",
      "port" : 99999, // sshポート番号
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env production"
    },
    "dev" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/development",
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env dev"
    }
  }
}
実際にsetupが成功すると、ecosystem.jsonで指定したpath配下に、次のようなディレクトリが作成されます。
foo@bar:/var/www/production$ ls -la
total 20
drwxrwxr-x  4 root root 4096 Nov 20 00:48 .
drwxrwxr-x  5 root root 4096 Nov 20 00:48 ..
-rw-rw-r--  1 node node   48 Nov 20 00:12 .deploys
lrwxrwxrwx  1 node node   20 Nov 20 00:12 current -> /var/www/production/source
drwxrwxr-x  4 node node 4096 Nov 14 00:57 shared
drwxrwxr-x 12 node node 4096 Nov 19 00:03 source

deploy

実際にデプロイするのは、

$ pm2 deploy ecosystem.json production
のコマンドです。これにより、リポジトリからのチェックアウトがなされ、ecosystem.jsonのpost-deployに指定したコマンドを実行します。デフォルトのecosystem.jsonではpm2によるプロセスの起動or再起動を行うコマンドが指定されています。例えば、npmやbowerのパッケージのインストール後に、nodeプロセスの再起動を、という場合は、↓のように書いてできました。
{
  : (省略)
  "post-deploy" : "npm install && bower install && pm2 startOrRestart ecosystem.json --env production"
  : (省略)
}

その他

pm2のデプロイ関連のコマンドを実行すると、/tmp/pm2-deploy.log にログが出力されます。ssh経由で発行したコマンドなども記録されますんで、デバッグやら何やらに参照するとよさそうです。

2014/06/03

express.jsでconnect-assetsを使う。

Railsには、asset pipelineという仕組みがあって、クライアントサイドのcoffeescriptやsassのソースを結合・圧縮してクライアントに配信することができるけど、node.js + express.jsのアプリケーションでは、同じようなことができないかな、と思って調べてみた。

connect-assets

すると、connect-assetsというライブラリを発見した。connect-assetsのREADMEに、"Transparent file compilation and dependency management for Node’s connect framework in the spirit of the Rails 3.1 asset pipeline."とあるように、Rails3.1で導入されたasset pipelineの仕組みをnode.jsのconnectフレームワーク上で実現するライブラリのようで、asset pipelineのように、分割されたjavascriptファイルやcssファイルを結合・圧縮してくれる。ソースがcoffeescriptやless、stylus、sassなどを使って書かれている場合でも使える。

mincer

connect-assetsは、内部でmincerを使っている。 mincerは、Railsのasset pipelineで使われているsprocketsのjavascriptポーティングライブラリ。 mincerの提供する構文に従って依存するライブラリを記述すると、それらをすべて結合したファイルを生成してくれる仕組みを提供する。 mincerは、内部でjavascriptの圧縮、cssの圧縮を行う。 ソースがcoffeescriptや、less、stylus、sassなどで書かれている場合は、コンパイルした上で圧縮することもできる。 connect-assetsのデフォルトだと、mincerに対して、Javascriptの圧縮器としてuguify-jsを、cssの圧縮機としてcssoを指定している。

使ってみる。

というわけで、connect-assetsを使ってみた。環境は、

  • node.js 0.10.28
  • express.js 4.2.0
  • connect-assets 3.0.1

インストール

npmでインストール。

$ npm install connect-assets --save
$ npm install less --save

cssにlessを使っているので、lessもインストールした。(less-middlewareは使わない。)

app.jsの記述

app.jsにconnect-assetsの設定を書く。 ↑のpathsには、ソースファイルのパスを指定する。 assets/jsはjavascriptのソースディレクトリ、assets/cssはCSSのソースディレクトリ(lessファイルもココに置いている)、componentsはbowerでインストールしたパッケージ群が入っている前提。 buildDirは、コンパイル・結合・圧縮後のファイルの出力ディレクトリ。

依存関係の定義

connect-assetsを使う上にあたり、mincerが理解できる形式で依存関係を定義したファイルを作成する必要がある。 mincerに対する依存関係の指定は、次のようなファイルで行う。

HTML(jade)側はどうするか?

HTML(jade)側で、connect-assetsが出力するファイルを参照するために、jadeファイルで次のコードを書く必要がある。

buildの有無

app.jsのconnect-assetsに対する設定で、buildオプションを指定することで、build(=結合・圧縮)の有無を変更できる。
デフォルトだと、

  • 開発環境では、build無し
  • 本番環境では、build有り
というオプションとなっている。この開発環境や本番環境は、NODE_ENVで切り替える。

2014/05/06

express.jsなプロジェクトでbowerを使ってパッケージを管理する。

bowerというパッケージ管理ツールがある。これは、Webサイト構築時に利用する様々なJavascriptやらcssといった外部のリソースを、パッケージとして管理するためのオープンソース。例えば、jQueryのバージョンが上がったからダウンロードしなくちゃとか、このライブラリはどこから持ってくればいいのか、とか、どこのディレクトリに配置すればいいの?とか、一度決めてしまえばそれでいいのだろうけど、bowerを使ってbowerの振る舞いに乗っかることで、外部のリソースに関する管理の手間が省けそう。

以前「node(express.js)でbootstrap3を使う、npmで簡単に。」を書いた際に、終わりの方に課題として、 ”bootstrapのJavascriptはどうすんのさ? これを楽する方法がまだわかっていませんorz。 node_modules/twitter-bootsrap-3.0.0の中にあるjsファイルをpublic/javascripts配下にコピーして使っているけど、これは今後の課題です。” と書いたけど、コレ対する解にもなる。

bowerの使い方。

bowerの基本的な使い方は簡単で、npmとかgemとか使ったことのある人なら、すぐに使えると思った。具体的な使い方は、↓のリンクが参考になります。

express.jsなプロジェクトでbowerを使う。

express.jsだとサーバーサイドで使うライブラリは、packages.jsonに書いてnpmで管理するのが基本的なパッケージ管理手法と思ってる。で、bowerはクライアントサイドで使うJavascriptやらを管理するために使う、ってことになる。

express.jsなプロジェクトにbowerを適用する。

bowerを適用するには、

$ cd express_project_root
$ bower init
を実行する。bower initは、最終的にbower.jsonを出力コマンドで、いくつかの設定を対話的に入力していく。実際のbower.jsonは、
{
  "name": "プロジェクト名",
  "version": "0.0.0",
  "homepage": "プロジェクトページヘのURL",
  "authors": [
    "名前 <メールアドレス>"
  ],
  "moduleType": [
    "node"
  ],
  "license": "MIT",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "components",
    "test",
    "tests"
  ],
}
のようになり、bowerでパッケージを管理する準備が出来た状態。

パッケージをインストールする。

例えば、jqueryを使うとする。bowerでインストールするには、

$ bower install jquery --save
とすると、プロジェクトルートにbower_componentsというディレクトリが生成され、その下にパッケージがインストールされる。また、--saveオプションを指定することで、bower.jsonに書き込まれる(この仕組みは、npmと同じですね。)。
.
├── app.js
├── bin
├── bower.json       # <= jqueryへの依存が定義される。
├── bower_components # <= この配下にパッケージがインストールされる。
├── node_modules
├── package.json
├── public
├── routes
└── views
したがって、npmやgemと同じ要領で、予め利用するパッケージがわかっているときは、bower.jsonにつらつらと書いてから、bower installすればいいし、後から利用するパッケージを増やす時は、bower install package_name --saveとすれば良さそう。

パッケージのインストール先をbower_componentsを以外にする。

bowerはデフォルトで、./bower_components配下にパッケージをインストールする。このままだと、ビューでJavascriptを読み込むのに、bower_components/jquery/dist/jquery.min.jsとかがscriptタグのsrc属性に登場することになるけど、bower云々がクライアント側のコードに出てくるのは避けたいので、インストール先のディレクトを変えてみる。具体的には、

$ less .bowerrc
{
  "directory": "components",
  "json": "bower.json"
}
というファイルを作って、"directory"を指定する(ここでは、componentsというディレクトリ名にしている)。そして、このディレクトをexpress.jsにスタティックなコンテンツを含むディレクトリであることを教えてあげれはよい。app.jsに↓を追記する。
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'components'))); // <= コレを追記する。

2014/04/24

three.jsで球を円運動させて太陽系の惑星を描いた。

three.jsの勉強中、単純なオブジェクトを円運動させる方法を知りたくて、それなら調べながら、太陽系の惑星たちの公転運動を描いてみようと思い至った。

球を描く

惑星なのでほぼ球だろう、ということでthree.jsが提供してくれているオブジェクトを使って、太陽と水星〜海王星までを球として表現してみた。3Dのオブジェクトを作るには、Geometry、Material、Meshの3つを使うのが基本だと思っていて、今回各天体を球として表現するのに、

  • THREE.MeshLambertMaterial
  • THREE.SphereGeometry
  • THREE.Mesh
の3つを使った。で、太陽をJavascriptのオブジェクトとして、↓のように書いてみた。
Sun = function() {
  this.material = new THREE.MeshLambertMaterial({ color: 0xff0000 });
  this.geometry = new THREE.SphereGeometry(109, 64, 64);
  this._mesh = new THREE.Mesh(this.geometry, this.material);
}

Sun.prototype = {
  constractor: Sun,
  get mesh() {
    return this._mesh;
  }
}
この太陽を3D空間に配置するには、
var sun = new Sun();
scene.add(sun.mesh);
とすればいい、と。

惑星は、Planetっていうオブジェクトをprototype継承させて個々の惑星を作ってやった。Planetは、

Planet = function(radiusRate, orbitalRadiusRate, color, omegaRate) {
  this.radiusBase = 4;
  this.orbitalRadiusBase = 400;
  this.radiusRate = radiusRate !== undefined ? radiusRate : 1.0
  this.orbitalRadiusRate = orbitalRadiusRate !== undefined ? orbitalRadiusRate : 1.0;
  this.color = color !== undefined ? color : 0x0000ff;
  this._omegaRate = omegaRate !== undefined ? omegaRate : 1;

  this._material = new THREE.MeshPhongMaterial({ color: this.color });
  this._geometry = new THREE.SphereGeometry(this.radiusBase * this.radiusRate, 64, 64);
  this._mesh = new THREE.Mesh(this._geometry, this._material);
  this._mesh.position.x = - this.orbitRadiusBase * this.orbitalRadiusRate;
  this._mesh.position.z = - this.orbitRadiusBase * this.orbitalRadiusRate;

  this._circleGeometry = new THREE.CircleGeometry(this.orbitalRadiusBase * this.orbitalRadiusRate, 2560);
  this._circleGeometry.vertices.shift();
  this._circleMaterial = new THREE.LineBasicMaterial({
    color: 0x111111
    // opacity: 0.1
    // linewidth: 0.01
  });
  this._circle = new THREE.Line(this._circleGeometry, this._circleMaterial);
  this._circle.rotation.x = 90 * Math.PI / 180;
};

Planet.prototype = {
  constractor: Planet,
  get material () {
    return this._material;
  },
  get geometry () {
    return this._geometry;
  },
  get mesh () {
    return this._mesh;
  },
  get circle() {
    return this._circle;
  },
  pivot: function(time) {
    var theta = 1.047 / this._omegaRate * time;
    this._mesh.position.x = Math.cos(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
    this._mesh.position.z = Math.sin(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
  }
};
のようなオブジェクトになった。コンストラクタの引数radiusRateorbitalRadiusRateは、それぞれ地球の半径を1として何倍か、地球の公転軌道半径を1として何倍か、を指定するようにした。それと、omegaRateっていうのは、地球の公転の角速度(rad/s)を1として何倍か、を指定するもので、公転運動の処理で使ってる。さらには、一応公転軌道(=円)を3D空間に表示しようと思って、circleっていう属性を定義した。円を描くのも、例のGeometry,Material,Meshの3点セットが必要だけど、three.jsは円に特化したオブジェクトを定義していて、実際に使ったのは、
  • THREE.CircleGeometry
  • THREE.LineBasicMaterial
  • THREE.Line
の3つ。これもsceneに追加してあげないと表示されないから、例えば、地球は、
Earth = function() {
  Planet.call(this, 1.0, 1.0, 0x0000ff, 1.0);
};
Earth.prototype = Object.create(Planet.prototype);
というオブジェクトを書いて、
var earth = new Earth();
scene.add(earth.mesh);
scene.add(earth.circle);
としてあげた。

円運動

円運動は、単位時間あたり何ラジアン進むか、が重要。で、今回は試しに1年を1分に見立てて色々と計算してみた。つまり、地球は1分かけて太陽の周りを1周する。その場合の地球の角速度は1.047(rad/sec)になった(あってます?)ので、これを使って瞬間瞬間の座標を計算してオブジェクトの位置を変えていけばよさそうだ、と。

で、今回のは、y=0平面上で公転させるってことにすると、xとzの値を時間と角速度と半径から求めることができるなぁ、と思い、結果出来たのが上述のPlanetオブジェクトのpivotというメソッド(↓再掲)。

pivot: function(time) {
    var theta = 1.047 / this._omegaRate * time;
    this._mesh.position.x = Math.cos(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
    this._mesh.position.z = Math.sin(theta) * this.orbitalRadiusBase * this.orbitalRadiusRate;
  }

実際に動かしてみる

実際に動くページをThe Solar System 3Dで公開しました。マウスでグリグリ、コロコロできたり。とりあえず、当初の目的であった、オブジェクトを円運動させる方法はわかったので良かった。

2014/03/30

node(express.js)でcsrf対策する。

node(express.js)でcsrfに対する対策を施す方法について書いてみる。といっても、express.jsはcsrf対策のためのミドルウェアを提供しているので、その使い方の話。(ここで使っているexpress.jsのバージョンは3.4.8です。)

express.jsのcsrfミドルウェア

express.jsが提供するミドルウェアに、csrf っていうのがあってコレを使うと簡単にcsrf対策ができる。

使い方 - app.js

expressコマンドでアプリケーションを作ると、app.jsというファイルが出来て、この中にアプリケーションやサーバの設定を書くんだけど、その中で次のコードを書く。

// use session support.
app.use(express.session());

// use csrf middleware.
app.use(express.csrf());
app.use(function(req, res, next) {
  res.locals._csrf = req.csrfToken();
  next();
});
前述のこのページにあるとおり、csrfミドルウェアを使うには、session()よりも下に書けってあるので、注意が必要。

使い方 - view

csrfミドルウェアが生成してくれるトークンをformに埋める必要があるので、viewでformを書くときには、

form(action='/some_action', method='form')
  input(type='hidden', name='_csrf', value='#{_csrf}')
  :
のように、hiddenに_csrfのトークンを埋めておく。(これはテンプレートエンジンにjadeを使った場合の例)

これで、postなリクエストにcsrfトークンが含まれていなかったり、不正なトークンが含まれていると、expressが検出してエラーを上げてくれるようになる。

2014/03/23

twitter-bootstrapを使う時のベーシックなlayout.jade

twitter-bootstrapをexpressjsなアプリに適用するにあたって、jadeのレイアウト(layout.jade)にbootstrapのcssとjavascriptを埋めます。ベーシックなレイアウトをgistに上げました。

node(expressjs)なアプリをデプロイする、capistrano3で簡単に。

node(expressjs)なアプリを作って、capistrano2でデプロイしていたのだけど、capistrano3が登場してずいぶんスマートになったとのことで、capistrano3に載せ替えてみた、という話です。

capistranoって何?

失礼なほどざっくり言ってしまえば、capistranoはrubyで書かれたデプロイツールで、gitやsvnなどのリポジトリからモジュールを取得、デプロイ先のしかるべきディレクトリに配置し、dbの変更、assetsの生成、プロセスの再起動なんかを自動でやってくれるすぐれものです。 capistrano2っていうのが長く広く使われていたところに、capistrano3が登場していろいろとスマートになったようです。

capistrano + node

nodeなアプリを対象とするにあたり、リモート(デプロイ先)でのnodeのパスを正しく設定したり、npmでライブラリ群をインストールしたり、っていうところをどうやるのか、というのが肝になるのかなぁ、と思っていたら、

っていうのが既にあったので、使わせて頂きました。

capistrano-nvm

capistrano上で動作するnvmタスクを提供してくれる。 ローカルなnvmにも、システムワイドなnvmにも対応している。僕のサーバはnvmをシステムワイドで入れているので助かった。([node] nvmをシステムワイドに適用する。)

capistrano-npm

capistrano上で動作するnpmタスクを提供してくれる。 Railsアプリのデプロイプロセスでbundle installを実行するように、npm installを走らせる。 もともとcapistrano-npmだけ追加してやったらnpmのパス(、つまりnode関連のパス)が解決できずどうしたものか、とはまっていたところに、capistrano-nvmと併せて使ったらば解決できたので、セットで使うのがいいのかと。

deploy

実際にデプロイするには、

  1. リモートホスト(デプロイ先ホスト)の環境設定
  2. capistranoのインストール
  3. capistrano-nvmのインストール
  4. capistrano-npmのインストール
  5. Capfile, deploy.rbの作成
  6. deploy
という流れになりますね。

リモートホスト(デプロイ先ホスト)の環境設定

リモートで作業するユーザとSSHの設定が基本になります。 ユーザ作って、ディレクトリ掘って、SSHでフォワードできれば良さそう。 capistranoの本家サイトにある、Authentication & Authorisationのページのとおりにやりました。

capistrano,capistrano-nvm,capistrano-npmのインストール

gemコマンドでも、bundle経由でもいいと思います。今回はgemコマンド叩いてインストールしてしまいました。

$ gem install capistrano
$ gem install capistrano-nvm
$ gem install capistrano-npm

Capfile, deploy.rbの作成

ここがcapistrano2から変わったところの1つで、2の頃はcapifyっていうコマンドがあって、一番最初にcapifyしていたのが、 cap installに変わりました。 cap install すると、Capfileとdeploy.rbとかstaging.rbとかproduction.rbが作られます。環境別の設定ファイルのひな形が生成されます。いわゆるマルチステージに対応しています。stagingっていうのは、順productionというのか、本番の手前っていう位置づけの環境と考えるといいと思います。

Capfileではそのプロジェクトにおけるcapistranoの環境を書きます。 deploy.rbとdeploy/*.rbには、デプロイに関する詳細やタスクを書きます。 自作でタスクを作る場合は、lib/capistrano/tasksに拡張子.capを作ります。

今回は、カスタムタスクはなしで、Capfile、deploy.rb、production.rbだけ弄って、それぞれ次のように書きました。

# Capfile
# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
#   https://github.com/capistrano/rvm
#   https://github.com/capistrano/rbenv
#   https://github.com/capistrano/chruby
#   https://github.com/capistrano/bundler
#   https://github.com/capistrano/rails
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
# require 'capistrano/bundler'
# require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'
require 'capistrano/nvm' # <= 追加
require 'capistrano/npm' # <= 追加

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
# config/deploy.rb
# config valid only for Capistrano 3.1
lock '3.1.0'

set :application, 'application_name'
set :repo_url,    'ssh://hostname.your.repo/path/to/your_repo.git'

# Default branch is :master
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }

# Default deploy_to directory is /var/www/my_app
# set :deploy_to, '/var/www/my_app'
set :deploy_to, '/var/www/application_name'

# Default value for :scm is :git
# set :scm, :git

# Default value for :format is :pretty
# set :format, :pretty

# Default value for :log_level is :debug
# set :log_level, :debug

# Default value for :pty is false
# set :pty, true

# Default value for :linked_files is []
# set :linked_files, %w{config/database.yml}

# Default value for linked_dirs is []
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
set :linked_dirs, %w{log node_modules}

# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Default value for keep_releases is 5
# set :keep_releases, 5

set :nvm_type, :system
set :nvm_node, 'v0.10.26'
set :nvm_map_bins, %w{node npm}

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # Your restart mechanism here, for example:
      # execute :touch, release_path.join('tmp/restart.txt')
      execute :sudo, :restart, 'name_of_upstart_script'
    end
  end

  after :publishing, :restart

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
      # within release_path do
      #   execute :rake, 'cache:clear'
      # end
    end
  end

end

deploy

ここまで準備ができたところで、デプロイします。 capistrano2の頃のように、cap deploy:setupとかはもう要らない。いきなり、 cap deployでよい。

$ cap production deploy

2014/03/14

node(express.js)でbootstrap3を使う、npmで簡単に。

express.jsを使ったnodeなWebアプリを作っていて、twitter-bootstrap使いたいな、と思った。かつて、bootstrap2の頃、本家からダウンロードして、cssとjavascriptをpublicに置いてできたー、とか思ったこともあったけど、npmとかないのかな?って思って探したらあった、じゃあ使ってみよう、という話です。

less-middlewareとtwitter-bootstrap-3.0.0

今回使ってみたのは、

の2つです。 less-middlewareは、express.jsがデフォルトで使用するメタCSS。twitter-bootstrap-3.0.0は、自分でpackage.jsonに書いてインストールしましたよ。
{
  "name": "appname",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.4.8",
    "jade": "*",
    "less-middleware": "*",
    "twitter-bootstrap-3.0.0": "*",
    :
  }
}

app.jsでless-middlewareの設定を書く。

twitter-bootstrap-3.0.0がインストールできたらば、app.jsに手を入れます。
いろいろとmiddlewareの登録をしている部分で、 var bootstrapPath = path.join(__dirname, 'node_modules', 'twitter-bootstrap-3.0.0');

app.use(require('less-middleware')({
  src:    path.join(__dirname, 'assets', 'less'),
  paths:  [path.join(bootstrapPath, 'less')],
  dest:   path.join(__dirname, 'public', 'stylesheets'),
  prefix: '/stylesheets'
}));
のようにless-middlewareを登録します。この記述は、
  • lessのソースは、assets/less配下に置く。
  • bootstrapPathの下のlessもlessのコンパイル対象に含める。
  • コンパイルして出来たcssファイルは、public/stylesheets配下に置く。
  • prefixは、lessのページに"Path which should be stripped from the public pathname."とあるけど、イマイチよくわかっていません。
という具合になります。
これで、bootstrapのlessはnpmに任せられるようになります。bootstrapをカスタマイズするには、assets/lessの下の自前lessファイルに書いていけば、カスタマイズできる、と。

2014-03-16追記

less-middlewareのバージョンが上がると、上述のオプションの指定の仕方が変わるそうで。 Migration 0.1.x 0.2.0 · emberfeather/less.js-middleware Wikiに詳しい説明がありますね。0.2.1-betaっていうのが今の時点で使えて、上の指定をするとエラーとなるので、次のように直したら、うまくいった。

var less = require('less-middleware');
var bootstrapPath = path.join(__dirname, 'node_modules', 'twitter-bootstrap-3.0.0');

app.use(less(path.join(__dirname, 'assets', 'less'),
             { dest: path.join(__dirname, 'public'),
               preprocess: {
                 path: function(pathname, req) {
                   return pathname.replace('/stylesheets', '');
                 }
               }
             },
             { paths:  [path.join(bootstrapPath, 'less')] }
            ));

bootstrapのJavascriptはどうすんのさ?

これを楽する方法がまだわかっていませんorz。
node_modules/twitter-bootsrap-3.0.0の中にあるjsファイルをpublic/javascripts配下にコピーして使っているけど、これは今後の課題です。

2014/01/26

rails+MySQLでdouble型カラムを扱うモンキーパッチ

背景

ruby2.1とrails4を使ってアプリを作っている。DBはMySQLを使っていて、わけあってあるテーブルの列をdouble型にしたいと思って。 カラムの列を変更するmigrationを作ろうと思った時に、そもそもdouble型のカラムを作るにはどうするんだっけ、ってなって、 Webを調べてみて、解がみつかったので試したところ、ちょっと不都合が生じて、それじゃあモンキーパッチを書いてみよう、という話です。

MySQLのdouble型を利用するmigration

まず、MySQLのdouble型の列を使うには、

add_column :table_name, :column, :float, limit: 53
のようなmigrationを書くとできる。(これは、既存のテーブルにカラムを追加するmigration)

型に:floatを指定して、:limitに53を指定する。参考にしたのは、

limit: 53は、MySQLのfloat型に精度を指定して定義する際に、精度が24〜53の場合は倍精度な浮動小数点型として扱われ、すなわちdouble型になるから、という風に理解している。(MySQL :: MySQL 5.6 Reference Manual :: 11.2.3 Floating-Point Types (Approximate Value) - FLOAT, DOUBLE)

問題点

上述のmigrationでカラムを追加すると、確かにdouble型のカラムになる。が、問題点が1つ。bundle exec rake db:migrateした時に、db/schema.rbが更新されるんだけど、このファイル内の当該カラムには、limit: 53が指定されない。結果、bundle exec rake db:test:prepareで、テスト環境のスキーマを更新した時に、当該カラムの型はfloatとして作成されてしまい、期待どおりにデータが扱えなくなってしまう。

ついでにいうと、本来double型を使いたいのに、:float, limit: 53って書くのもの、ちょっと違和感ありますね。

モンキーパッチ

db/schema.rbを手で直すってのも、あれなんで、なんとかならないものか、思って調べ始めたら、次のようなページを発見。

このページのハックを適用すると、
#add_column :table_name, :column, :float, limit: 53
# が↓のように書けるようになる。
add_column :table_name, :column, :double
となり、問題点の2つ目に対する解になりそう。が、db/schema.rbの問題は解決しないなぁ。もうちょっと調べるか、と思ってrailsのソースをみてたら、ActiveRecord::ConnectionAdapters::Columnというクラスのextract_limit(sql_type)というメソッドをみつけた。このメソッドは、どうやらSQLの型をみて、db/schema.rbを吐き出すときに:limitに何を指定するかを判断するものっぽい。各RDBMS用のアダプターでこれらをオーバーライドしているし。

ということで、次のようなモンキーパッチをconfig/initializers/add_double_to_activerecord.rbとして、作っておくことに。

module CustomColumnTypes 
  def double(*args)
    if args.last.is_a? Hash
      args.last[:limit] = 53
      args.last[:null]  = true
    end
    float *args
  end
end
module ColumnWithDouble
  def extract_limit(sql_type)
    case sql_type
    when /double/i
      53
    else
      $1.to_i if sql_type =~ /\((.*)\)/
    end
  end
end
module ActiveRecord
  module ConnectionAdapters
    class Table
      include CustomColumnTypes
    end
    class TableDefinition
      include CustomColumnTypes
    end
    class Column
      prepend ColumnWithDouble
    end
  end
end

これでdb/schema.rbにも無事にlimit: 53が出力されるようになった。

課題

上のパッチでは、ActiveRecord::ConnectionAdapters::Columnに対して振る舞いを変えているんだけど、僕がdoubleをサポートしたいのはMySQLの場合のだけだから、実はうまくない。なので、MySQL用のアダプタをイジる方法に変えるべきだなぁ、と思ってます。

2014/01/12

railsでREST Web APIをつくってrspecでテストする。

railsでRESTfulなAPIを書いていて、テストはrspecを使うと決めていたのだが、対象がRESTful APIということで、 何か気にすることはあるのだろうか。テストというか、設計というか、これまで実践していたことと、 今回調べて新たに発見したことを合わせて、纏めておく。

テスト対象

テスト対象は、rails4で作ったRESTfulなAPI。全てのAPIはJSONフォーマットのみ対応。 つまり、htmlとかxml形式の応答はしない。今回試したのはRails4。

rspecとその他のgem

テスト環境にいくつかgemを追加して、テストの準備をする。 追加するのは、

の各gem。それぞれのgemの用途と設定をちょっと書きます。

rspec

テストを記述する。rspec、railsアプリのrspecでのテストの仕方は、

が参考になる。

railsアプリのテストでrspecを利用するための手順

-T付きでrails newする。

デフォルトのrailsアプリのテストは、Test::Unitが使われ、test用のディレクトリが生成される。-TオプションをつけるとTest::Unitが無効になり、testというディレクトリが生成されない(rspecのテストコードは、specディレクトリに入れる。)

$ rails new application_name -T

Gemfileの記述

Gemfileに以下を追加する。

group :development, :test do
  gem 'rspec-rails'
end

bundle installの実行

bundlerを使ってrpsecをインストールする。

$ bundle install

rspecの初期設定

rspecをrailsアプリに組み込むと、railsコマンドのgeneratorにrspec:installが追加される。 追加されているかは、rails g -hを実行すれば確認できる。

$ rails g -h
(略)
Rspec:
  rspec:controller
  rspec:helper
  rspec:install
  rspec:integration
  rspec:mailer
  rspec:model
  rspec:observer
  rspec:scaffold
  rspec:view
(略)
rspec:installを実行して、specディレクトリを作るとともに、spec_helper.rbを生成する。
$ rails g rspec:install
ここまでが、rails上でrspecを使うためのベーシックな手順。

simplecov

simplecovは、ruby用のコードカバレッジ計測ツールで、railsでも使える。 rspecとも簡単に連動できるし、生成されるレポートも見やすい。

Gemfileの記述

Gemfileに以下を追加する。

group :development, :test do
  gem 'simplecov'
end

bundle installの実行

bundlerを使ってsimplecovをインストールする。

$ bundle install

rspecとsimplecovの連携

spec/spec_helper.rbの先頭に次のコードを追加するだけで、rspecが動くたびにカバレッジを計測してくるようになる。 計測結果は、デフォルトではcoverageディレクトリにhtmlファイルとして出力される。

require 'simplecov'
SimpleCov.start 'rails'

guard-rspec

rspecを使ってテストを書いている場合、コードを直してspecを直して、rake specで全てのテストが問題なく通ることを確認して、というサイクルで開発していくことになる(このサイクル自体はrspecを使う場合に限らないけど。)。この時に修正したモジュールに対するspecの実行とか、全てのspecの実行とか、いちいちコマンドを叩いているのが面倒になる。そんなとき、guardを使うとspecの実行を自動化できるようになる。guardは、プロジェクト内のファイルの変更を監視して、変更が発生すると、ある動作を実行する、というもの。なので、rubyファイルやspecファイルをguardに監視させて、変更が発生したらテストを実行する、というように使う。


に詳しい説明があってとても参考になる。

Gemfileの記述

Gemfileに以下を追加する。

group :development, :test do
  gem 'guard-rspec'
end

bundle installの実行

bundlerを使ってgurad-rspecをインストールする。

$ bundle install

guardの設定

guardは、Guardfileの記述に従って動作する。Guardfileは、

$ bundle exec guard init rspec
で生成する。Guardfileに監視対象と、実行するspecの組み合わせを追加していくのだけど、これについては後述する。

guardの実行

guardを実行するには、

$ bundle exec guard
とする。すると、
13:36:21 - INFO - Guard is using NotifySend to send notifications.
13:36:21 - INFO - Guard is using TerminalTitle to send notifications.
13:36:21 - INFO - Guard::RSpec is running
13:36:21 - INFO - Guard is now watching at '監視対象パス'
[1] guard(main)> 
と表示され、監視が始まる。guardのプロンプトで、"all"(またはEnter)と打つと、全てのspecが実行される。

spring

guardを使ってrspecを動かす手間がかなり省けるようになると、次に気になるのがspecの実行時間。specの量が増えてくると、実行時間が長くなるし、そもそも起動時間も長くなって時間が勿体無く感じてくる。 springを使うと、railsの環境を先読みしてくれるようになるので、様々なプロセスの起動が速くなる。これをguardと組み合わせて使うことで、guardが実行するrspecを高速化することができる。

Gemfileの記述

Gemfileに以下を追加する。

group :development, :test do
  gem 'spring'
end

bundle installの実行

bundlerを使ってspringをインストールする。

$ bundle install

guardとspringの連携

guardとspringを合わせて使うには、Guardfileをちょっと修正するだけでよい。

guard :rspec, spring: true do # spring: true を追加する。
  :(略)
end

factory_girl

railsでrspecを使うときのテストデータに関して面倒なことがある。デフォルトだと、spec/fixturesディレクトリにテーブル(model)単位にymlファイルを作ってテスト時にロードして、っていうやり方になるけど、これだとモデル間のリレーションを考慮したテストデータづくりが非常に面倒くさいし、データが増えると管理できなくなる。この問題は、facotyr_girlを使うことで対応できる。factory_girlは、fixturesに定義していたymlをrubyで記述できるDSLを提供してくれている。そのため、データの定義やデータ間の関連がスッキリ書けるようになる。

などが参考になる。

Gemfileの記述

Gemfileに以下を追加する。

group :development, :test do
  gem 'factory_girl_rails'
end

bundle installの実行

bundlerを使ってfactory_girlをインストールする。

$ bundle install

JSONを返すRESTなAPI

ここまではどちらかというと、あまりJSONとかRESTとかとは直接関係しない、rspecを使ったテストを効率良く進めるための話題。 ここからはJSONを返すRESTなAPIのテストに関する話題。

にもろに影響を受けている。

APIのバージョニングを考慮する。

実際に経験したことでは、スマートフォンアプリをクライアントとするAPIを作っていて、アプリの機能を追加・変更して行く過程で、 API自体にバージョンの概念が必要になって、APIのリソースのURLにバージョン番号を埋めた、ってことがある。具体的には、例えばユーザ情報を取得するAPIが、

https://api.exapmle.com/users/id.json?id=xxxx
のように定義していて、ある時点から応答するデータの内容が大幅に変える必要がある、という場合。やったのは、
https://api.exapmle.com/v2/users/id.json?id=xxxx
という新しいURLを定義して、元々のAPIと並行して運用するということをした。このやり方(URLにバージョンを埋める)は、Twitter APIやFoursquare APIでも同じようなやり方をしているので、結構メジャーなソリューションなのかと思っている。railsでの実現方法は、

が参考になる。

APIのフォーマットをJSONに限定する。

railsのコントローラをgenerateコマンドで定義すると、デフォルトではhtmlを応答するアクションが生成されるけど、APIを作っている場合、htmlを応答することはまず無いし、一度JSONを返すと決めたら、後々xmlだとか他のフォーマットに対応させる、という変更が発生することも少ないのではないか、と思っている。なので、始めからJSONのみに限定したAPIにしてしまえば、設計もテストも楽になると考えた。

railsであるURLがデフォルトでJSONのみに対応するようにするには、

  • routes.rb
  • controller
  • view
を意識的にイジる必要がある。

config/routes.rb

例えば、ユーザ情報に関するAPIをrailsのresourcesを使いつつ、JSONに限定する場合は、

namespace :v1, defaults: { format: 'json' } do
  resources :users
end
としてあげると、通常必要となるURLの最後の".json"が不要となる。

controller

コントローラ側でJSONのみに対応させるには、

module V1
  class UsersController < ApplicationController
    respond_to :json

    def show
      @user = User.find(id: params[:id])
    end
  end
end
のように、先頭でrespond_toを読んであげれば個々のアクションでrespond_toを書く必要がなくなる。

view

JSON形式の応答も、独立したviewを作成することができる(知らなかった・・)。rails3.2から導入されたjbuilderというgemを使って、例えば上述のusers#showに対するviewは、app/views/v1/users/show.json.jbuilder というファイルを作ればよい。

jbuilderに関する解説もRailsCastの、


がわかりやすい。簡単にJSONのviewが作れるので感動的。

ここまでは、JSONを返すAPIの設計の話だったけど、次はテストの話。

テストは、Request Specに書く。

前述の「Rails API Testing Best Practices With RSpec」によると、APIのテストは、(Controller Specではなく、)Request Specに書くべき、ということらしい。 APIの呼び出しと応答(JSON)をテストする場合は、コントローラ単体というよりは、ルーティング、コントローラ、モデルなど各スタック間のIntegration Testに近いイメージで、rspecのRequest Specは、それがテストできるように設計されているから、ということっぽい。

JSON Helperをこしらえる。

JSONを返すアクションのテストを書くと、確かに

JSON.parse(response.body)
が頻発する。これをテストごとにいちいち書かずに、モジュールを作ってDRYに行こうぜ、と。
# spec/support/request_helpers.rb
module Requests
  module JsonHelpers
    def json
      @json ||= JSON.parse(response.body)
    end
  end
end
というモジュールを作っておいて、spec_helperで、
RSpec.configure do |config|

  config.include Requests::JsonHelpers, type: :request

end
としておけば、簡単にパースされたJSONオブジェクトにアクセスできるようになる。

まとめ

railsでREST Web APIをつくってrspecでテストする、という場合に、テスト関連ライブラリの準備や、APIの設計方法、テストのポイントをグワーっと書いてみました。中身が薄かったり、言葉足らずだったり、まとめきれてない感じもあります。更に精進して、改善していきたいと思います。

2014/01/09

railsでテストデータの管理にfactory_girlを使うのが良さそう。

RSpecを使ってテストを書いていて、 コードの量が増えるとテストで使うデータの管理が煩わしくなるなぁ、と思っていた。 何しろfixturesをymlで書くので、1対多とか多対多の関連を持つデータを定義、管理するのが面倒。

そこで今更ながら知ったのが factory_girl というgemです。

A library for setting up Ruby objects as test data.
とあり、RSpecのfixtures地獄から解放してくれるスグレモノっぽい。

factory_girl導入

Gemfileに、

group :test do
  gem 'factory_girl_rails'
end
を足して、
$ bundle
すると利用可能に。

データの定義

例えば、ymlに、

default:
  id: 1
  email: test@test.com
  password: password
  password_confirmation: password
と書いて定義していたレコードが、
FactoryGirl.define do
  factory :user do
    id 1
    email 'test@test.com'
    password 'password'
    password_confirmation 'password'
  end
end
という具合にRubyコードで定義できるようになる。

データの利用

ymlによるfixturesを利用する場合は、各specで、

fixtures :users
でテストデータを投入して、
before(:each) do
  @user = users :default
end
とか書いて、データを読み込んでいたが、factory_girlを使うと、
before(:each) do
  @user = FactoryGirl.create(:user)
end
ってするだけで、データが読み込める。このcreateは、DBにレコードをinsertし、そのレコードをfindして返すみたいな動作をするけど、 他にも、
  • create
  • build
  • attributes_for
  • build_stubbed
というメソッドが用意されていて、テストケースに応じて使い分けることができる。

詳しいドキュメントは、githubのGETTING_STARTED.mdにあるので、よく読んで使い方をマスターしたい。

2014/01/07

express.jsで自作faviconを使用する。

express.js

express.js では、デフォルトでexpress.js自身が提供するfaviconを配信するよう、コードが自動生成される。具体的には、express.jsが提供するアプリケーションのひな形を生成するコマンドを、

 $ express 
のように実行すると、
  • app.js
というファイルが生成され、
:(略)

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('less-middleware')({ src: path.join(__dirname, 'public') }));
app.use(express.static(path.join(__dirname, 'public')));

:(略)
というコードが出力される。上記の、
express.favicon()
が、デフォルトのfaviconの使用を定義するコード。

express.favicon()

express.favicon()は、nodeアプリのためのミドルウェアで、connect というのがあって、こいつが提供する機能の1つ。詳しくは、ここにドキュメントがあった。読むと、

By default serves the connect favicon, or the favicon located by the given path.
とあるので、デフォルトだとconnectのfaviconを配信するし、パスが与えられればそいつを配信するよ、ってことだね。(同じページにソースも載っている。)

自作のfaviconを配信する。

なので、次のように自作favicon.icoへのパスをfavicon()関数に渡してあげればよさそう。

app.use(express.favicon(__dirname + '/public/images/favicon.ico', {
  maxAge: 2592000000 // キャッシュの有効期限
}));

2014/01/05

three.js + tween.js でMatrixのアレっぽいものを作ってみた。

「three.jsでカレンダーを3Dにしてみた。」でthree.jsとtween.jsを使ったカレンダーを作ってみたけど、もうちょっと凝ったカレンダーが作れそうとか思っていて、実験として何か作ってみようということで、映画「マットリックス」に出てくるアレっぽいものを作ってみた。

tween.jsのonComplete関数を使って、落下するコードを3Dオブジェクトとしても、DOM要素としても消滅させて、新たなコードを生成して、tweenのアニメーション対象として追加する、というコードにしてみたけど、それでいいのかどうか。とりあえず、http://simalabs.com/labs/3d/matrixで動かしています(chromeで動作確認済み)。リクエストがあれば、コードを載せますので、コメントいただければと思います。