在大多數情況下,在現有的 v0.9 專案中執行 sails lift 應該可以直接運作。核心貢獻者已採取許多步驟,盡可能簡化升級過程,如果您遵循控制台中的棄用訊息,應該就能順利完成。
Sails v0.10 帶來了一些重大變更。以下章節概述了已變更的內容、主要的錯誤修復、增強功能和新功能,以及關於如何將您的 v0.9.x Sails 應用程式升級到 v0.10 的基本教學。
Connect multipart 中介軟體即將正式棄用。但由於此模組在 Sails v0.9 和 Express v3 中被用作內建的 HTTP body parser,因此對於依賴 req.files
的 v0.9 Sails 專案來說,這是一個破壞性變更。
在 v0.10 中,Sails 預設包含 skipper,這是一個 body parser,允許串流檔案上傳,而無需將臨時檔案緩衝到磁碟。對於一般的文件上傳使用案例,Skipper 捆綁了對上傳到本機磁碟(透過 skipper-disk)的支援,但串流上傳可以外掛到其任何支援的适配器。
有關範例/文件,請參閱 Skipper 儲存庫以及 Sails 文件中關於 req.file()
的說明。
Body parser 的工作是解析傳入的 multipart HTTP 請求的「body」。有時,「body」包含文字參數,但有時,它包含檔案上傳。
Connect multipart 是很棒的程式碼,它支援 multipart 請求中的檔案上傳和文字參數。但與大多數同類模組一樣,它透過將檔案上傳緩衝到磁碟來完成此操作。這可能會迅速淹沒伺服器的可用磁碟空間,並且在許多情況下會暴露嚴重的 DoS 攻擊漏洞。
Skipper 的獨特之處在於它支援串流檔案上傳,但也保持對請求 body 中元資料的支援(即 JSON/XML/urlencoded 請求 body 參數)。它使用一些啟發式方法來確保只有您期望的檔案被外掛並被 blob 适配器接收,而其他(可能惡意的)檔案欄位則被忽略。
重要事項!
為了使 Skipper 正常運作,您必須在檔案上傳請求中將所有文字參數放在檔案參數之前傳送至伺服器。一旦 Skipper 看到第一個檔案欄位,它就會停止等待文字參數(這是為了避免不必要/不安全的檔案資料緩衝)。
與 Sails 中的大多數事物一樣,您可以使用任何您喜歡的 Connect/Express/Sails 相容的 bodyparser。若要切換回 connect-multipart,或任何其他 body parser(如 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
}
};
message
socket(即「comment」)事件現在是 modelIdentity
(其中「modelIdentity」根據呼叫 publish*()
方法的模型而有所不同)。Model.watch()
。create
、update
和 destroy
的事件現在為 created
、updated
和 destroyed
。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
}
// ...
}
現在,您訂閱模型的 identity
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
的參數,指定您是訂閱模型類別(class room)還是訂閱一個或多個模型實例。它實際上是一種方法來做兩件非常不同的事情。
現在,您使用 Model.subscribe()
僅訂閱模型實例(記錄)。您還可以指定您想要聽取的事件「context」或類型。例如,如果您只想接收關於實例更新的消息,您可以呼叫 User.subscribe(req, myUser, 'update')
。如果在呼叫 .subscribe()
時未給出 context,則將使用模型類別的 autosubscribe 屬性指定的所有 context。
若要訂閱模型建立事件,您現在可以使用 Model.watch()
。訂閱後,您的用戶端將在每次使用藍圖路由在該模型上建立新記錄時收到訊息,並且也會自動訂閱新的實例。
請記住,在使用藍圖時,用戶端不再自動訂閱 class room。這必須手動完成。
最後,如果您想查看來自所有模型的所有 pubsub 訊息,您可以存取 firehose
,這是一個僅供開發使用的工具,用於廣播關於所有發生在您的模型上的訊息。您可以使用 sails.sockets.subscribeToFirehose(socket)
訂閱 firehose,或在前端向 /firehose
發出 socket 請求。每當模型被建立、更新、銷毀、新增至、從中移除或收到訊息時,firehose 都會廣播 firehose
事件。這有效地取代了先前 Sails 版本中使用的 message
事件。
若要查看新 pubsub 方法的實際範例,請參閱 SailsChat。
先前,在 schema: true
的情況下,如果您將不符合模型屬性中宣告的預期型別的屬性值傳送到 .create()
或 .update()
,您傳入的值仍然可以在模型的生命週期回呼中存取。
在 Sails/Waterline v0.10 中,情況不再如此。傳遞到 .create()
和 .update()
的值會在您的生命週期回呼執行之前進行型別轉換。受影響的生命週期回呼包括 beforeUpdate()
、beforeCreate()
和 beforeValidate()
。
如果您在任何模型中使用 beforeValidation
或 afterValidation
模型生命週期回呼,您應該將它們變更為 beforeValidate
或 afterValidate
。Waterline 中進行此變更是為了符合其他生命週期回呼的樣式(例如 beforeCreate
、afterUpdate
等)。
.done()
的舊(/令人困惑?)含義已被棄用。
在 Sails <= v0.8 中,執行 ORM 查詢的語法是 Model. [ … ] .done( cb )
。在 v0.9 中,當新增 promise 支援時,Model. [ … ] .exec( cb )
成為建議的替代方案,因為 .done()
在 promise 規範中具有特殊含義。但是,.done()
的原始用法保持不變,以使從 v0.8 升級到 v0.9 更容易。
但從 Sails/Waterline v0.10 開始,.done()
的原始含義已正式棄用,以便在未來實現更穩健的 promise 實作,以及可外掛的 promise 庫支援(例如,選擇 Q
或 Bluebird
等)。
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
切換,它會建立一個 myApp/assets/linker folder
,其中包含 js
、styles
和 templates
資料夾。在這個新版本中,不會建立 myApp/assets/linker
資料夾。從 myApp/assets/js
和 myApp/assets/scripts
資料夾開始編譯 CoffeeScript 和 Less 現在是預設行為。
在 v0.10 中,您現在可以產生自己的自訂伺服器回應。
與之前一樣,我們自動為您建立了一些。它們現在在 myApp/api/responses/
中產生,而不是在 config 目錄中產生 myApp/config/500.js
和其他 .js
回應。
若要遷移,您需要建立一個新的 v0.10 專案,並將 myApp/api/responses
目錄複製到您現有的應用程式中。然後,您將修改適當的 .js 檔案,以反映您在回應邏輯檔案(500.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
檔案產生的。
若要設定模型以使用特定的适配器,您現在必須在 connection
金鑰中指定它們,而不是 adapters
。
例如
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 中,所有版面配置路徑都相對於您應用程式的 views 路徑。換句話說,版面配置的相對路徑不再從視圖自己的路徑解析 - 現在始終從 views 路徑解析。這使得更容易理解正在使用的檔案,尤其是在版面配置檔案具有相似名稱時
return res.view('auth/login', {
layout: 'auth/someLayout'
});