在大多数情况下,在现有的 v0.9 项目中运行 sails lift 应该可以正常工作。核心贡献者已经采取了一些措施来使升级尽可能容易,如果您按照控制台中的弃用消息操作,您应该可以很好地完成。
Sails v0.10 带有一些重大更改。以下部分提供了有关更改内容、主要错误修复、增强功能和新功能的高级概述,以及有关如何将您的 v0.9.x Sails 应用程序升级到 v0.10 的基本教程。
Connect 多部分中间件 将很快正式弃用。但是,由于此模块在 Sails v0.9 和 Express v3 中用作内置 HTTP 主体解析器,因此对于依赖 req.files
的 v0.9 Sails 项目来说,这是一个重大更改。
在 v0.10 中,Sails 默认包含 skipper,它是一个主体解析器,允许流式文件上传而无需将临时文件缓冲到磁盘。对于普通的上传用例,Skipper 带有捆绑的本地磁盘上传支持(通过 skipper-disk),但是流式上传可以插入到其任何支持的适配器中。
有关示例/文档,请参阅 Skipper 存储库以及 Sails 文档上的 req.file()
。
主体解析器的工作是解析传入的多部分 HTTP 请求的“主体”。有时,“主体”包含文本参数,但有时包含文件上传。
Connect 多部分是出色的代码,它支持多部分请求中的文件上传和文本参数。但是,与大多数同类模块一样,它通过将文件上传缓冲到磁盘来实现这一点。这会迅速压垮服务器的可用磁盘空间,在很多情况下会暴露严重的 DoS 攻击漏洞。
Skipper 的独特之处在于它支持流式文件上传,但也维护对请求主体中元数据的支持(即 JSON/XML/urlencoded 请求主体参数)。它使用一些启发式方法来确保只有您期望的文件被插入并由 blob 适配器接收,而其他(可能是恶意的)文件字段被忽略。
重要!
要使 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
}
};
message
套接字(即“comment”)事件现在是 modelIdentity
(其中“modelIdentity”根据调用 publish*()
方法的模型而不同)。Model.watch()
。create
、update
和 destroy
的事件现在是 created
、updated
和 destroyed
。发布订阅的最大变化是 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
}
// ...
}
现在,您订阅模型的身份
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
的参数。它实际上是一种方法来做两件截然不同的事情。
现在,您使用 Model.subscribe()
仅订阅模型实例(记录)。您还可以指定您想了解的事件“上下文”或类型。例如,如果您只想收到有关实例更新的消息,您将调用 User.subscribe(req, myUser, 'update')
。如果没有在对 .subscribe()
的调用中给出上下文,则将使用模型类自动订阅属性指定的所有上下文。
要订阅模型创建事件,您现在可以使用 Model.watch()
。订阅后,您的客户端将在使用蓝图路由在该模型上创建新记录时收到消息,并且还会自动订阅新实例。
请记住,在使用蓝图时,客户端不再自动订阅课堂。这必须手动完成。
最后,如果您想查看来自所有模型的所有发布订阅消息,您可以访问 firehose
,这是一个仅限开发的工具,它会广播有关发生在模型上的所有内容的消息。您可以使用 sails.sockets.subscribeToFirehose(socket)
订阅 firehose,或者通过向 /firehose
发出套接字请求在前端订阅。每当模型被创建、更新、销毁、添加到、从...中移除或发送消息时,firehose 都会广播 firehose
事件。这实际上取代了以前 Sails 版本中使用的 message
事件。
要查看新发布订阅方法在实践中的示例,请参阅 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 文件夹
,并在其中包含 js
、styles
和 templates
文件夹。在这个新版本中,不会创建 myApp/assets/linker
文件夹。从 myApp/assets/js
和 myApp/assets/scripts
文件夹中编译 CoffeeScript 和 Less 是默认行为。
在 v0.10 中,您现在可以生成自己的自定义服务器响应。
与以前一样,我们为您自动创建了一些响应。现在,它们不是在 config 目录中生成 myApp/config/500.js
和其他 .js
响应,而是在 myApp/api/responses/
中生成。
要进行迁移,您需要创建一个新的 v0.10 项目,并将 myApp/api/responses
目录复制到您的现有应用程序中。然后,您将修改相应的文件,以反映您在响应逻辑文件中(500.js 等)所做的任何自定义。
sails-disk
,在新的 Sails 项目中默认使用,现在以略微不同的方式存储数据。如果你在 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 中,所有布局路径都相对于你的应用程序的视图路径。换句话说,布局的相对路径不再从视图自身的路径解析——现在它总是从视图路径解析。这使得更容易理解正在使用哪个文件,尤其是在布局文件具有类似名称时。
return res.view('auth/login', {
layout: 'auth/someLayout'
});