Sails.jsでRailsチュートリアルをやってみる

最近、RailsライクなNode.jsのwebフレームワークとして、[Sails.js](https://sailsjs.com/)の存在を知りました。

折角なので[Railsチュートリアルの第2章](https://railstutorial.jp/chapters/toy_app?version=5.1#cha-a_toy_app)をベースにモデルを作成する所までをやってみようと思います。

## Sails.jsのインストール
```
$ yarn global add sails
```

## プロジェクトの作成
[localhost:1337](http://localhost:1337)にアクセスすれば、デフォルトのページが表示されます。

```:sails
$ sails new sails-tutorial
$ cd sails-tutorial
$ sails lift
```

=============================

```:rails
$ rails new rails-tutorial
$ cd rails-tutorial
$ rails server
```


## 「Hello, World!」を表示
### コントローラーを生成
Railsの場合はプロジェクトの作成時に`ApplicationController`が生成されますが、Sails.jsでは生成されないので、生成します。

```:sails
$ sails generate controller application hello
```

==========================

```:rails
$ sails generate controller application hello
```

### 「Hello, World!」を返す処理を実装
```js:api/controllers/ApplicationController.js
/**
 * ApplicationController
 *
 * @description :: Server-side logic for managing applications
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {
  /**
   * `ApplicationController.hello()`
   */
  hello: function (req, res) {
    return res.send('Hello, World!');
  }
};
```

==========================

```rb:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  def hello
    render html: "Hello, World!"
  end
end
```

### ルーティングの設定
```js:config/routes.js
module.exports = {
  '/': 'ApplicationController.hello'
}
```

==========================

```rb:config/routes.rb
Rails.application.routes.draw do
  root 'application#hello'
end
```

## Usersリソースのマイグレーション
### データベースの設定
RailsはデフォルトでSQLiteが使われますが、Sails.jsでは対応していません。
Sails.jsでは代わりに[sails-disk](https://www.npmjs.com/package/sails-disk)を利用することで、ローカルにデータベースを構築することが出来ます。

因みに、Postgres,Oracle,MySQL,MongoDBなど主要なDBも普通に接続情報を記述すれば利用可能です。

```js:config/connections.js
module.exports.connections = {
  // sails-disk is installed by default.
  localDiskDb: {
    adapter: 'sails-disk'
  }
};
```

```js:config/models.js
module.exports.models = {
  connection: 'localDiskDb'
}
```

==========================

```rb:config/database.yml
default: &default
  adapter: sqlite3
  pool: 5
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3
```

### Usersモデルの生成
Sails.jsにはRailsの`scaffold`のようなコマンドは存在しないので、モデルとコントローラーをそれぞれ生成します。
（`generate api`コマンドで両方のファイルを一度に生成可能ですが、空のモデルが作成されるだけなので、別々で生成しています。）

Sails.jsではモデルに対応する同名のコントローラーが存在すれば、自動でルーティングをしてくるようになります。

```:sails
$ sails generate model user name:string, email:string
info: Created a new model ("User") at api/models/User.js!

$ sails generate controller user
info: Created a new controller ("user") at api/controllers/UserController.js!
```

==========================

```:rails
$ rails generate scaffold User name:string email:string
      invoke  active_record
      create    db/migrate/20171206150716_create_users.rb
      create    app/models/user.rb
      ...
```

### マイグレーションの実行
Sails.jsでは`sails lift`の実行時に自動でマイグレーションが実行される（Production環境では自動で実行されない）ので、Railsのようにコマンドで実行することが出来ません。
細かくマイグレーションを管理したい場合は、[sequelize/sequelize](https://github.com/sequelize/sequelize)　や [tgriesser/knex](https://github.com/tgriesser/knex)などの外部ツールを利用してください。

```js:config/models.js
module.exports.models = {
  connection: 'localDiskDb',
  migrate: 'alter' // マイグレーションの起動設定をしておく必要がある
}
```

==========================

```
$ rails db:migrate
```

### Usersリソースにアクセスする
Railsは画面ベースになるので省略します。

```sails
# ユーザーの生成
$ curl -X POST http://localhost:1337/user -d "name=太郎&email=tarou@tarou.com"
{
  "name": "太郎",
  "email": "tarou@tarou.com",
  "createdAt": "2017-12-06T16:30:04.224Z",
  "updatedAt": "2017-12-06T16:30:04.224Z",
  "id": 1
}%

# ユーザーの一覧を取得
$ curl localhost:1337/user
[
  {
    "name": "太郎",
    "email": "tarou@tarou.com",
    "createdAt": "2017-12-06T16:30:04.224Z",
    "updatedAt": "2017-12-06T16:30:04.224Z",
    "id": 1
  }
]%
```