既存のv0.9プロジェクトで`sails lift`を実行するだけで、ほとんどの場合動作するはずです。コアコントリビューターはアップグレードをできるだけ容易にするために多くの措置を講じており、コンソールに表示される非推奨メッセージに従えば、問題なく完了するはずです。
Sails v0.10にはいくつかの大きな変更が加えられています。以下のセクションでは、変更点の概要、主要なバグ修正、機能強化、新機能、そしてv0.9.x Sailsアプリをv0.10にアップグレードする方法の基本的なチュートリアルを提供します。
Connect multipartミドルウェアはまもなく正式に非推奨となります。しかし、このモジュールはSails v0.9とExpress v3の組み込みHTTPボディパーサーとして使用されていたため、`req.files`に依存するv0.9 Sailsプロジェクトにとっては破壊的変更となります。
v0.10では、デフォルトでSailsにskipperが含まれています。これは、一時ファイルをディスクにバッファリングすることなく、ファイルアップロードのストリーミングを可能にするボディパーサーです。一般的なファイルアップロードのユースケースでは、Skipperはローカルディスクへのアップロード(skipper-disk経由)のバンドルサポートを提供しますが、ストリーミングアップロードはサポートされているアダプターのいずれかにプラグインできます。
例/ドキュメントについては、Skipperリポジトリと`req.file()`に関するSailsドキュメントを参照してください。
ボディパーサーの役割は、着信するマルチパートHTTPリクエストの「ボディ」を解析することです。「ボディ」にはテキストパラメーターが含まれる場合もありますが、ファイルアップロードが含まれる場合もあります。
Connect multipartは優れたコードであり、マルチパートリクエストのファイルアップロードとテキストパラメーターの両方をサポートしています。しかし、同種のモジュールのほとんどと同様に、これはファイルをディスクにバッファリングすることで実現しています。これにより、サーバーの利用可能なディスク容量がすぐに不足し、多くの場合、深刻なDoS攻撃の脆弱性を露呈します。
Skipperは、ファイルアップロードの**ストリーミング**をサポートしながら、リクエストボディのメタデータ(つまり、JSON/XML/URLエンコードされたリクエストボディパラメーター)もサポートするという点でユニークです。期待されるファイルのみがブロブアダプターにプラグインされ、受信されるように、いくつかのヒューリスティックを使用して、他の(悪意のある可能性のある)ファイルフィールドが無視されます。
重要!
Skipperを動作させるには、ファイルアップロードリクエストで、サーバーへの**テキストパラメーターをファイルパラメーターの前に含める**必要があります。Skipperが最初のファイルフィールドを検出すると、テキストパラメーターの待機を停止します(これは、ファイルデータの不要な/安全でないバッファリングを回避するためです)。
Sailsのほとんどのことと同様に、好きなConnect/Express/Sails互換のボディパーサーを使用できます。**connect-multipart**または他のボディパーサー(**formidable**や**busboy**など)に切り替えるには、アプリのhttp構成を変更します。
新しいブループリントアクション(`findOne`)が追加されました。たとえば、`FooController`と`Foo`モデルがある場合、`/foo/5`にリクエストを送信すると、`FooController`の`findOne`アクションが実行されます。`findOne`アクションがない場合は、代わりに`findOne`ブループリントアクションが使用されます。`/foo`に送信されたリクエストは、引き続きfindコントローラー/ブループリントアクションを実行します。
ポリシーはv0.9とまったく同じように機能しますが、考慮すべき新しい点があります。上記で説明したより具体的な`findOne()`ブループリントアクションの導入により、ポリシーマッピング構成でそれを明示的に処理する必要があります。
たとえば、v0.9アプリの`policies.js`構成で`DoveController`の`find`アクションへのアクセスを防止しているとします。
module.exports.policies = {
'*': true,
DoveController: {
find: false
}
};
restブループリントルートが有効になっていると仮定すると、これは`/dove`と`/dove/14`の両方のリクエストへのアクセスを防止します。しかし、v0.10では`/dove/14`は実際には`findOne`アクションを実行するため、明示的に処理する必要があります。
module.exports.policies = {
'*': true,
DoveController: {
find: false,
findOne: false
}
};
pubsubで最大の変更点は、Socket.ioイベントがイベントを発行したモデルの名前の下で発行されるようになったことです。以前は、クライアントは`message`イベントをリッスンし、含まれているデータに基づいてどのモデルから来たのかを判断する必要がありました。
socket.on('message', function(cometEvent) {
if (cometEvent.model == 'user') {
// Handle inbound messages related to a user record
}
else if (cometEvent.model === 'product') {
// Handle inbound messages related to a product record
}
// ...
}
現在は、モデルのIDを購読します。
socket.on('user', function(cometEvent) {
// Handle inbound messages related to a user record
});
socket.on('product', function (cometEvent) {
// Handle inbound messages related to a product record
});
これは、フロントエンドコードの構造化に役立ちます。
クライアントをモデルに購読する方法も変更されました。以前は、`Model.subscribe`に渡したパラメーターに基づいて、モデルクラス(クラスルーム)または1つ以上のモデルインスタンスを購読するかどうかを指定していました。これは、実際には2つの非常に異なることを行うための1つの方法でした。
現在は、`Model.subscribe()`を使用して、モデルインスタンス(レコード)のみに購読します。また、聞きたいイベント「コンテキスト」またはタイプを指定することもできます。たとえば、インスタンスの更新に関するメッセージのみを取得したい場合は、`User.subscribe(req, myUser, 'update')`を呼び出します。`.subscribe()`への呼び出しでコンテキストが指定されていない場合、モデルクラスのautosubscribeプロパティで指定されたすべてのコンテキストが使用されます。
モデル作成イベントを購読するには、`Model.watch()`を使用できるようになりました。購読すると、ブループリントルートを使用して新しいレコードがそのモデルに作成されるたびにクライアントにメッセージが送信され、新しいインスタンスにも自動的に購読されます。
ブループリントを使用している場合、クライアントはクラスルームに自動的に購読されなくなっていることを覚えておいてください。これは手動で行う必要があります。
最後に、すべてのモデルからのすべてのpubsubメッセージを確認したい場合は、`firehose`にアクセスできます。これは開発専用のツールで、モデルで発生するすべてのイベントに関するメッセージをブロードキャストします。`sails.sockets.subscribeToFirehose(socket)`を使用してfirehoseを購読するか、フロントエンドで`/firehose`へのソケットリクエストを行うことができます。firehoseは、モデルが作成、更新、削除、追加、削除、またはメッセージが送信されるたびに`firehose`イベントをブロードキャストします。これは、以前のSailsバージョンで使用されていた`message`イベントを効果的に置き換えます。
新しいpubsubメソッドの動作例については、SailsChatを参照してください。
以前は、`schema: true`の場合、モデルの属性で宣言された期待される型と一致しない属性値を`.create()`または`.update()`に送信すると、渡した値はモデルのライフサイクルコールバックで引き続きアクセスできました。
Sails/Waterline v0.10では、これはもはや当てはまりません。`.create()`および`.update()`に渡された値は、ライフサイクルコールバックが実行される前に型変換されます。影響を受けるライフサイクルコールバックには、`beforeUpdate()`、`beforeCreate()`、`beforeValidate()`が含まれます。
モデルのいずれかで`beforeValidation`または`afterValidation`モデルライフサイクルコールバックを使用していた場合は、`beforeValidate`または`afterValidate`に変更する必要があります。この変更は、他のライフサイクルコールバック(例:`beforeCreate`、`afterUpdate`など)のスタイルに合わせるためにWaterlineで行われました。
`done()`の古い(/混乱を招く?)意味は非推奨になりました。
Sails <= v0.8では、ORMクエリを実行するための構文は`Model. [ … ] .done( cb )`でした。v0.9では、Promiseサポートが追加されたため、`done()`はPromise仕様で特別な意味を持つため、`Model. [ … ] .exec( cb )`が推奨される代替手段になりました。しかし、v0.8からv0.9へのアップグレードを容易にするために、`done()`の元の使用方法に変更はありませんでした。
しかし、Sails/Waterline v0.10以降、より堅牢なPromise実装と、プラグ可能なPromiseライブラリのサポート(例:`Q`または`Bluebird`など)を可能にするために、`done()`の元の意味は正式に非推奨になりました。
Sails v0.10は、データモデル間の関連付けを導入します。関連付けに関して行った作業は大部分が追加的なものであるため、既存のモデルは引き続き動作するはずです。つまり、これはコードの記述量を減らし、アプリの保守性を向上させる強力な新機能であるため、活用することをお勧めします。Sailsで関連付けを使用する方法については、ドキュメントを参照してください。
関連付け(または「リレーション」)は、実際には特別な属性です。文字列または整数の値の代わりに、モデルのインスタンスまたはモデルインスタンスのコレクションを指定できます。これは、NoSQLデータベースにJSONとして保存するオブジェクト(`{...}`)または配列(`[{...}, {...}]`)のようなものと考えてください。違いは、Sailsでは、これがサポートされているすべてのデータベースで機能し、異なるデータベースやデータベースの種類間でのポピュレート(つまり、結合)も可能にすることです。
Sailsはしばらくの間、コード生成をサポートしていました(例:`sails generate controller foo`)が、v0.10では、この機能をより拡張可能で、オープンで、Sailsコミュニティのすべての人がアクセスできるようにしたいと考えていました。それを念頭に置いて、v0.10にはコマンドラインツールの完全な書き換えと、プラグ可能なジェネレーターが付属しています。`sails generate blog foo`を実行して、Sails上に構築された新しいブログを作成できるようにしたいですか?`blog`ジェネレーターを作成し(`sails generate generator blog`を実行)、テンプレートを追加し、新しいテンプレートをコピーするようにジェネレーターを構成します。その後、`sails-generate-blog`というnpmモジュールを公開することで、コミュニティにリリースできます。Yeomanジェネレーターとの互換性もロードマップに含まれています。
ここでの大きな変更点は、新しいAPIを作成する方法です。過去には`sails generate new_api`を呼び出していました。これにより、適切な場所に`new_api`という名前の新しいコントローラーとモデルが生成されました。これは現在、`sails generate api new_api`を使用して行われます。
同じCLIコマンドを使用して、モデルとコントローラーを個別に生成することもできます。
また、--linker
スイッチは使用できなくなりました。以前のバージョンでは、--linker
スイッチを指定すると、内部にjs
、styles
、templates
フォルダを持つmyApp/assets/linker
フォルダが作成されました。この新しいバージョンでは、myApp/assets/linker
フォルダは作成されません。CoffeeScriptとLessのコンパイルは、myApp/assets/js
およびmyApp/assets/scripts
フォルダからデフォルトで実行されるようになりました。
v0.10では、独自のサーバーレスポンスを生成できるようになりました。
以前と同様に、自動的に作成されるレスポンスがいくつかあります。myApp/config/500.js
などの.js
レスポンスをconfigディレクトリに生成する代わりに、myApp/api/responses/
に生成されるようになりました。
移行するには、新しいv0.10プロジェクトを作成し、myApp/api/responses
ディレクトリを既存のアプリケーションにコピーする必要があります。その後、レスポンスロジックファイル(500.jsなど)で行ったカスタマイズを反映するように、適切な.jsファイルを修正します。
新しいSailsプロジェクトでデフォルトで使用されるsails-disk
は、データを少し異なる方法で保存するようになりました。0.9.xプロジェクトに一時データが保存されている場合は、それを消去して最初からやり直す必要があります。そのためには
プロジェクトのルートディレクトリから
$ rm .tmp/disk.db
config.adapters
(myApp/config/adapters.js
内)は、config.connections
になりました(新しいプロジェクトでは、これはmyApp/config/connections.js
に生成されます)。また、config.model
はconfig.models
になりました。
アプリケーションのデフォルトのconnection
(つまり、データベース)は、モデルでデフォルトで使用される文字列config.models.connection
として設定する必要があります。新しいプロジェクトは、デフォルトの接続を含む/config/models.js
ファイルと共に生成されます。
特定のアダプターを使用するようにモデルを設定するには、adapters
の代わりにconnection
キーで指定する必要があります。
例:
module.exports = {
connection: ['someMongoDatabase'],
attributes: {
name:{
type : 'string',
required : true
}
}
};
コントローラーブループリントのコントローラー設定オーバーライドを記述するオブジェクトリテラルは、
...
_config: {
blueprints: {
rest: true,
...
}
}
から
...
_config: {
rest: true,
...
}
Sails v0.9では、ビューのレンダリング時にカスタムレイアウトとしてauth/someLayout.ejs
を指定するために、次の構文を使用できました。
return res.view('auth/login',{
layout: 'someLayout'
});
しかし、Sails v0.10では、すべてのレイアウトパスはアプリケーションのビューパスを基準とします。つまり、レイアウトの相対パスはビュー自身のパスから解決されなくなりました。ビューパスから常に解決されるようになりました。これにより、特にレイアウトファイルの名前が類似している場合、どのファイルが使用されているかをより理解しやすくなります。
return res.view('auth/login', {
layout: 'auth/someLayout'
});