Sails v1.0 is here! Keep reading for a high-level overview of what's changed in this release, and to learn about some new features you might want to take advantage of in your app.
While working on this version of Sails, a lot of the decisions we made favored a better developer experience over backwards compatibility. Because of this, the upgrade to Sails 1.0 will involve dealing with more breaking changes than previous versions. But when you're finished, there'll be a much better chance that the features you're using in Sails are things that its author and maintainers understand thoroughly and use almost every day.
For more about the philosophy behind many of the breaking changes in 1.0, you can read Mike McNeil's in-depth explanation here.
Ready to upgrade your existing v0.12.x Sails app to version 1.0? To get started, we recommend using the Sails 1.0 upgrade tool, which will help with some of the most common migration tasks. To use the tool, first install Sails 1.0 globally with npm install -g sails@^1.0.0
and then run sails upgrade
. After the tool runs, it will create a report for you with a list of remaining items that need to be manually upgraded.
The checklist below covers the changes most likely to affect the majority of apps.
If your app still has errors or warnings on startup after following this checklist, or if you're seeing something unexpected, head back to this document and take a look further down the page. (One of the guides for covering various app components will probably be applicable.)
We've done a lot of work to make the upgrade process as seamless as possible, particularly when it comes to the errors and warnings you'll see on the console. But if you're stumped or have lingering questions about any of the changes below, feel free to drop by the Sails community Gitter channel. (If your company is using Sails Flagship, you can also chat directly with the Sails core team here.)
The upgrade tool does its best to help with some of these items, but it won’t change your app-specific code for you!
- Step 0: Check your Node version
- Step 1: Install hooks & update dependencies
- Step 2: Update configuration
- Step 3: Modify client-side code for the new blueprint API
- Step 4: Adopt the new release of Waterline ORM
If your app needs to support Node versions earlier than v4, you will not be able to upgrade to Sails 1.0, as Sails 1.0 no longer supports Node v0.x. The earliest version of Node supported by Sails 1.0 is Node 4.x.
Sails v1 introduces custom builds. This means that certain core hooks are now installed as direct dependencies of your app, giving you more control over your dependencies and making npm install sails
run considerably faster. So, the first thing you'll need to do is install the core hooks you're using. (And while you're at it, be sure to update the other dependencies mentioned in the list below.)
- Install the
sails-hook-orm
package into your app withnpm install --save sails-hook-orm
, unless your app has the ORM hook disabled. - Install the
sails-hook-sockets
package into your app withnpm install --save sails-hook-sockets
, unless your app has the sockets hook disabled. - Install the
sails-hook-grunt
package into your app withnpm install --save sails-hook-grunt
, unless your app has the Grunt hook disabled. - Install the latest version of your database adapter. For example, if you're using
sails-mysql
, donpm install --save sails-mysql@latest
. - Upgrade your
sails.io.js
websocket client withsails generate sails.io.js
. See the "Websockets" section below for more details.
Sails v1 comes with several improvements in app configuration. For example, automatic install of lodash and async can now be customized to any version, and view engine configuration syntax is now consistent with that of Express v4+. The most significant change to configuration, however, is related to one of the most exciting new features in Sails v1: datastores. To make sure you correctly upgrade the configuration for your database(s) and other settings, be sure to carefully read through the steps below and apply the necessary changes.
- Update your
config/globals.js
file (unless your app hassails.config.globals
set tofalse
)- Set
models
andsails
to have boolean values (true
orfalse
). - Set
async
andlodash
to either haverequire('async')
andrequire('lodash')
respectively, or elsefalse
. You may need tonpm install --save lodash
andnpm install --save async
, as well.
- Set
- Comment out any database configuration your aren’t using in
config/connections.js
. Unlike previous versions, Sails 1.0 will load all database adapters that are referenced in config files, regardless of whether they are actually used by a model. See the migration guide section on database configuration for more info. - The
/csrfToken
route is no longer provided to all apps by default when using CSRF. If you're utilizing this route in your app, you'll need to manually add it toconfig/routes.js
as'GET /csrfToken': { action: 'security/grant-csrf-token' }
. - If your app relies on action shadow routes (where every custom controller action is automatically mapped to a route), you’ll need to update your
config/blueprints.js
file and setactions
totrue
. This setting is nowfalse
by default. - If your app uses CoffeeScript or TypeScript see the CoffeeScript and TypeScript tutorials for update information.
- If your app uses a view engine other than EJS, you’ll need to configure it yourself in the
config/views.js
file, and you'll likely need to runnpm install --save consolidate
for your project. See the "Views" section below for more details. - If your
api
orconfig
folders and subfolders contain any non-source files, they’ll need to be moved. The exception is for Markdown (.md) and text (.txt) files, which will continue to be ignored. Sails will attempt to read all other files in those folders as code, allowing for more flexibility in choosing between Javascript dialects (see the notes about CoffeeScript and TypeScript above).
As well as having been expanded to include a new endpoint, there also are a couple of minor—but breaking—changes to the blueprint API that may require you to make changes to your client-side code.
- If your app uses blueprint routes, be aware that a couple of implicit "shadow" routes have had their HTTP method (aka verb) changed:
- If your app relies on the default socket notifications from blueprint actions, be aware that there have been some performance-related upgrades that change the structure of these messages somewhat:
- Sails no longer publishes separate
addedTo
notifications, one for each new member of a collection. Those individual notifications are now rolled up into a single notification, and the new message contains an array of ids (addedIds
) instead of just one. - Sails no longer publishes separate
removedFrom
notifications, one for each former member of a collection. Sails now rolls those up into a single notification, and the new message now contains an array of ids (removedIds
) instead of just one.
- Sails no longer publishes separate
The new release of Waterline ORM (v0.13) introduces full support for SQL transactions, the ability to include or omit attributes in result sets (aka "projections"), dynamic database connections, and more extensive granular control over query behavior. It also includes a major stability and performance overhaul, which comes with a few breaking changes to usage. The bullet points below cover the most common issues you're likely to run into with the Waterline upgrade.
- If your app relies on getting records back from
.create()
,.createEach()
,.update()
, or.destroy()
calls, you’ll need to update your model settings to indicate that you want those methods to fetch records (or chain a.fetch()
to individual calls). See the migration guide section oncreate()
,.createEach()
,.update()
, and.destroy()
results for more info. - If your app relies on using the
.add()
,.remove()
, and.save()
methods to modify collections, you will need to update them to use the new .addToCollection, .removeFromCollection, and .replaceCollection model methods. - Waterline queries will now rely on the database for case sensitivity. This means that in most adapters your queries will now be case-sensitive, whereas before they were not. This may have unexpected consequences if you are used to having case-insensitive queries. For more information on how to manage this for databases such as MySQL, see the case sensitivity docs.
- Waterline no longer supports nested creates or updates, and this change extends to the related blueprints. If your app relies on these features, see the migration guide section on nested creates and updates for more info.
- If your app sets a model attribute to
null
using.create()
,.findOrCreate()
or.update()
, you’ll need to change the type of that attribute tojson
, or use the base value for the existing attribute type, instead ofnull
(e.g.0
for numbers). See the validations docs for more info. - The
create
blueprint response is now fully populated, just like responses fromfind
,findOne
,update
anddestroy
. To suppress population of records, add aparseBlueprintOptions
to your blueprints config or to a specific route. See the blueprints configuration reference for more information. - If you're using
createEach
to insert large numbers of rows into a database, keep in mind that the Sails 1.0-compatible versions of most adapters now optimize thecreateEach
method to use a single query, instead of using one query per row. Depending on your database, per-request data size limits may apply. See the notes at the bottom of the.createEach()
reference page for more information. - The
size
property for attributes is no longer supported. Instead, you may indicate column size using thecolumnType
property. - The
defaultsTo
property for attributes may no longer be defined as a function. Instead, you will either need to hard-code a default value, or remove thedefaultsTo
entirely and update your code to determine the appropriate value for the attribute before creating new records. (This can either be handled before calls to.create()
/.createEach()
in your actions, or in the model'sbeforeCreate
).
The upgrade guide above provides for the most common upgrade issues that Sails contributors have encountered when upgrading various apps between version 0.12 and version 1.0. Every app is different, though, so we recommend reading through the points below, as well. Not all of the changes discussed will necessarily apply to your app, but some might.
- Several properties and methods on
req
now work a little differently:req.accepted
has been replaced withreq.accepts()
req.acceptedLanguages
andreq.acceptsLanguage()
have been replaced withreq.acceptsLanguages()
req.acceptedCharsets
andreq.acceptsCharset()
have been replaced withreq.acceptsCharsets()
- Several
req.options
properties related to blueprints are no longer supported. Instead, the newparseBlueprintOptions
method can be used to give you complete control over blueprint behavior. See the blueprints configuration reference for more information. - The
defaultLimit
andpopulate
blueprint configuration options are no longer supported. Instead, the newparseBlueprintOptions
method can be used to give you complete control over blueprint behavior. See the blueprints configuration reference for more information. - The
.findOne()
query method no longer supportssort
andlimit
modifiers, and will throw an error if the given criteria match more than one record. If you want to find a single record using anything besides aunique
attribute (like the primary key) as criteria, use.find(<criteria>).limit(1)
instead (keeping in mind that this will return an array of one item). autoPk
,autoCreatedAt
andautoUpdatedAt
are no longer supported as top-level model properties. See the migration guide section on model config changes for more information.- Dynamic finders (such as
User.findById()
) are no longer added to your models automatically. You can implement these yourself as custom model methods. - Model Instance Methods are no longer supported. This allows records returned from find queries to be plain JavaScript objects instead of model record instances.
- Custom
.toJSON()
instance methods are no longer supported. Instead, add acustomToJSON
method to the model class (outside of theattributes
dictionary). See the model settings documentation for more information. - The
.toObject()
instance method is no longer added to every record. When implementingcustomToJSON
for a model, be sure to clone the record using_.omit()
,_.pick()
or_.clone()
. autoUpdatedAt
timestamps can now be manually updated in calls to.update()
(previously, the passed-in attribute value would be ignored). The previous behavior faciliated the use of.save()
, which is no longer supported. Now, you can update theupdatedAt
if you need to (but generally you should let Sails do this for you!)beforeValidate
andafterValidate
lifecycle callbacks no longer exist. Use one of the many other lifecycle callbacks to tap into the query.afterDestroy
lifecycle callback now receives a single record. It has been normalized to work the same way as theafterUpdate
callback and call the function once for each record that has been destroyed rather than once with all the destroyed records.- Many resourceful PubSub methods have changed (see the PubSub section below for the full list). If your app only uses the automatic RPS functionality provided by blueprints (and doesn’t call RPS methods directly), no updates are required.
- The
.find()
model method no longer automatically coerces constraints that are provided for unrecognized attributes. For example, if you executePurchase.find({ amount: '12' })
, e.g. via blueprints (http://localhost:1337/purchase?amount=12), and there is no such "amount" attribute, then even if the database contains a record with the numeric equivalent (12
), it will not be matched. (This is only relevant when using MongoDB and sails-disk.) If you are running into problems because of this, either define the attribute as a number or (if you're using blueprints) use an explicitwhere
clause instead (e.g.http://localhost.com:1337/purchase?where={"amount":12}
). - Custom blueprints and the associated blueprint route syntax have been removed. This functionality can be replicated using custom actions, helpers, and routes. See the "Replacing custom blueprints" section below for more information.
- Blueprint action shadow routes no longer include
/:id?
at the end -- that is, if you have aUserController.js
with atickle
action, you will no longer get a/user/tickle/:id?
route (instead, it will be just/user/tickle
). Apps relying on those routes should add them manually to theirconfig/routes.js
file. sails.getBaseUrl
, deprecated in v0.12.x, has been removed. See the v0.12 docs forgetBaseUrl
for more information on why it was removed and how you should replace it.req.params.all()
, deprecated in v0.12.x, has been removed. Usereq.allParams()
instead.sails.config.dontFlattenConfig
, deprecated in v0.12.x, has been removed. See the original notes aboutdontFlattenConfig
for details.- The order of precedence for
req.param()
andreq.allParams()
has changed. It is now consistently path > body > query (that is, url path params override request body params, which override query string params). req.validate()
has been removed. Useactions2
instead.- The default
res.created()
response has been removed. If you’re callingres.created()
directly in your app, and you don't have anapi/responses/created.js
file, you’ll need to create one.
- On a related note, the Blueprint create action will now return a 200 status code upon success, instead of 201.
- The default
notFound
andserverError
responses no longer accept apathToView
argument. They will only attempt to serve a404
or500
view. If you need to be able to call these responses with different views, you can customize the responses by addingapi/responses/notFound.js
orapi/responses/serverError.js
files to your app. - The default
badRequest
orforbidden
responses no longer display views. If you don’t already have theapi/responses/badRequest.js
andapi/responses/forbidden.js
files, you’ll need add them yourself and write custom code if you want them to display view files. - The
connect-flash
middleware has been removed (soreq.flash()
will no longer be available by default). If you wish to continue usingreq.flash()
, runnpm install --save connect-flash
in your app folder and add the middleware manually. - The
POST /:model/:id
blueprint RESTful route has been removed. If your app is relying on this route, you’ll need to add it manually toconfig/routes.js
and bind it to a custom action. - The
handleBodyParserError
middleware has been removed; in its place, the Skipper body parser now has its ownonBodyParserError
method.- If you have customized the middleware order, you’ll need to remove
handleBodyParserError
from the array. - If you've overridden
handleBodyParserError
, you’ll need to instead overridebodyParser
with your own customized version of Skipper, including your error-handling logic in theonBodyParserError
option.
- If you have customized the middleware order, you’ll need to remove
- The
methodOverride
middleware has been removed. If your app utilizes this middleware:npm install --save method-override
- Make sure your
sails.config.http.middleware.order
array (inconfig/http.js
) includesmethodOverride
somewhere beforerouter
- Add
methodOverride: require('method-override')()
tosails.config.http.middleware
.
- The
router
middleware is no longer overrideable. Instead, the Express 4 router is used for routing both external and internal (aka “virtual”) requests. It’s still important to have arouter
entry insails.config.http.middleware.order
to delimit which middleware should be added before and after the router. - The query modifiers
lessThan
,lessThanOrEqual
,greaterThan
, andgreaterThanOrEqual
have been removed. Use the shorthand versions instead (<
,<=
,>
,>=
). - The
find one
andfind
blueprint actions now accept apopulate=false
rather thanpopulate=
to specify that no attributes should be populated. - The
add
andremove
blueprint actions now require that the primary key of the child record to add or remove be supplied as part of the URL, rather than allowing it to be passed on the query string or in the body. - The
destroy
blueprint action now requires that the primary key of the record to destroy be supplied as part of the URL, rather than allowing it to be passed on the query string or in the body. - The
sails.config.session.routesDisabled
setting has changed tosails.config.session.isSessionDisabled()
, a function. See theconfig/session.js
docs for more information on configuringisSessionDisabled()
. - The experimental “switchback-style” usage for Waterline methods is no longer supported. Only function callbacks may be used with Waterline model methods.
- The experimental
create
auto-migration scheme is no longer supported. It is highly recommended that you use a migration tool such as Knex to handle migrations of your production database. - The experimental
forceLoadAdapter
datastore setting is no longer supported. Instead, all adapters referenced inconfig/datastores.js
(formerlyconfig/connections.js
) are automatically loaded whenever Sails lifts. - The experimental
usage
route option has been removed. It is recommended that you perform any route parameter validation in your controller code. - The experimental “associated-item” blueprint shadow routes have been removed. These were routes like
GET /user/1/pets/2
, whose functionality can be replicated by simply using the much-clearer routeGET /pets/2
. - The experimental
.validate()
method in model classes (e.g.User.validate()
) is now fully supported, but its usage has changed. See the.validate()
docs for more information. - The ordering of attributes in the internal representation of model classes has changed (association attributes are now sorted at the bottom). This has the effect of causing tables created using
migrate: 'alter'
to have their columns in a different order than in previous versions of Waterline, so be aware of this if column ordering is important in your application. As a reminder, auto-migrations are intended to help you design your schema as you build your app. They are not guaranteed to be consistent regarding any details of your physical database columns besides setting the column name, type (including character set / encoding if specified) and uniqueness. - Using
_config
to link a controller to a model will no longer work. This was never a supported feature, but it was used in some projects to change the URLs that were mapped to the blueprint actions for a model. Please userestPrefix
instead. - The
find()
,destroy()
, andupdate()
methods ignoreundefined
attributes. These methods will strip undefined attributes from their search criteria, e.g.User.update({id: undefined}).with({ firstName: 'Finn'})
would update every user record. Read more about this in this Github issue
- The
sails.config.connections
setting has been deprecated in favor ofsails.config.datastores
. If you lift an app that still hassails.config.connections
configured, you’ll get a warning which you can avoid by simply changingmodule.exports.connections
inconfig/connections.js
tomodule.exports.datastores
. For your own sanity, it’s recommended that you also change the filename toconfig/datastores.js
. - The
sails.config.models.connection
setting has been deprecated in favor ofsails.config.models.datastore
. As above, changing the name of the property inconfig/models.js
should be sufficient to turn off any warnings. - Every app now has a default datastore (appropriately named
default
) that is configured to use a built-in version of thesails-disk
adapter. In Sails 1.0, the default value ofsails.config.models.datastore
isdefault
(rather thanlocalDiskDb
). The recommended approach to setting the default datastore for your models is to simply to add the desired configuration under thedefault
key inconfig/datastores.js
, and leave thedatastore
key inconfig/models.js
undefined, rather than the previous approach of settingdatastore
to (for example)myPostgresqlDb
and then adding amyPostgresqlDb
key toconfig/datastores.js
. This makes it a lot easier to change the datastore used by different environments (for instance, by changing the configuration of thedefault
datastore inconfig/env/production.js
). - All datastores that are configured in an app will be loaded at runtime (rather than only loading datastores that were being used by at least one model). This has the benefit of allowing the use of a datastore outside the context of an individual model, but it does mean that if you don’t want to connect to a certain database when Sails lifts, you should comment out that datastore connection config!
- The
.create()
,.update()
and.add()
model methods no longer support creating a new “child” record to link immediately to a new or existing parent. For example, given aUser
model with a singular association to anAnimal
model through an attribute calledpet
, it is not possible to setpet
to a dictionary representing values for a brand newAnimal
(aka a “nested create”). Instead, create the newAnimal
first and use its primary key to setpet
when creating the newUser
. - Similarly, the create, update and add blueprint actions no longer support nested creates.
- The
.update()
model method and its associated blueprint action no longer support replacing an entire plural association. If a record is linked to one or more other records via a “one-to-many” or “many-to-many” association and you wish to link it to an entirely different set of records, use the.replaceCollection()
model method or the replace blueprint action.
Remove any autoPK
, autoCreatedAt
and autoUpdatedAt
properties from your models, and add the following to your config/models.js
file:
attributes: {
createdAt: { type: 'number', autoCreatedAt: true, },
updatedAt: { type: 'number', autoUpdatedAt: true, },
id: { type: 'number', autoIncrement: true}, // <-- for SQL databases
id: { type: 'string', columnName: '_id'}, // <-- for MongoDB
}
This property was formerly used to indicate whether or not Waterline should create an id
attribute as the primary key for a model. Starting with Sails v1.0 / Waterline 0.13, Waterline will no longer create any attributes in the background. Instead, the id
attribute must be defined explicitly. There is also a new top-level model property called primaryKey
, which can be set to the name of the attribute that should be used as the model's primary key. This value defaults to id
for every model, so in general you won't have to set it yourself.
These properties were formerly used to indicate whether or not Waterline should create createdAt
and updatedAt
timestamps for a model. Starting with Sails v1.0 / Waterline 0.13, Waterline will no longer create these attributes in the background. Instead, the createdAt
and updatedAt
attributes must be defined explicitly if you want to use them. By adding autoCreatedAt: true
or autoUpdatedAt: true
to an attribute definition, you can instruct Waterline to set that attribute to the current timestamp whenever a record is created or updated. Depending on the type of these attributes, the timestamps will be generated in one of two formats:
- For
type: 'string'
, these timestamps are stored in the same way as they were in Sails 0.12: as timezone-agnostic ISO 8601 JSON timestamp strings (e.g.'2017-12-30T12:51:10Z'
). So if any of your front-end code is relying on the timestamps as strings it's important to set this tostring
. - For
type: 'number'
, these timestamps are stored as JS timestamps (the number of milliseconds since Jan 1, 1970 at midnight UTC).
Furthermore, for any attribute, if you pass new Date()
as a constraint within a Waterline criteria's where
clause, or as a new record, or within the values to set in a .update()
query, then these same rules are applied based on the type of the attribute. If the attribute is type: 'json'
, it uses the latter approach.
As of Sails v1.0 / Waterline 0.13, the default result from .create()
, .createEach()
, .update()
, and .destroy()
has changed.
To encourage better performance and easier scalability, .create()
no longer sends back the created record. Similarly, .createEach()
no longer sends back an array of created records, .update()
no longer sends back an array of updated records, and .destroy()
no longer sends back destroyed records. Instead, the second argument to the .exec() callback is now undefined
(or the first argument to .then()
, if you're using promises).
This makes your app more efficient by removing unnecessary find
queries, and it makes it possible to use .update()
and .destroy()
to modify many different records in large datasets, rather than falling back to lower-level native queries.
You can still instruct the adapter to send back created or modified records for a single query by using the fetch
method. For example:
Article.update({
category: 'health-and-wellness',
status: 'draft'
})
.set({
status: 'live'
})
.fetch()
.exec(function(err, updatedRecords){
//...
});
If the prospect of changing all of your app's queries seems daunting, there is a temporary convenience you might want to take advantage of. To ease the process of upgrading an existing app, you can tell Sails/Waterline to fetch created/updated/destroyed records for ALL of your app's
.create()
/.createEach()
/.update()
/.destroy()
queries. Just edit your app-wide model settings inconfig/models.js
:fetchRecordsOnUpdate: true, fetchRecordsOnDestroy: true, fetchRecordsOnCreate: true, fetchRecordsOnCreateEach: true,That's it! Still, to improve performance and future-proof your app, you should go through all of your
.create()
,.createEach()
,.update()
, and.destroy()
calls and add.fetch()
when you can. Support for these model settings will eventually be removed in Sails v2.
- For performance reasons, as of Sails v1.0 / Waterline 0.13, criteria passed into Waterline's model methods will now be mutated in-place in most situations (whereas in Sails/Waterline v0.12, this was not necessarily the case).
- Aggregation clauses (
sum
,average
,min
,max
, andgroupBy
) are no longer supported in criteria. Instead, see new model methods .sum() and .avg(). - Changes to limit and skip:
limit: 0
no longer does the same thing aslimit: undefined
. Instead of matching ∞ results, it now matches 0 results.- Avoid specifying a limit of < 0. It is still ignored, and acts like
limit: undefined
, but it now logs a deprecation warning to the console. skip: -20
no longer does the same thing asskip: undefined
. Instead of skipping zero results, it now refuses to run with an error.- Limit must be < Number.MAX_SAFE_INTEGER (...with one exception: for compatibility/convenience,
Infinity
is tolerated and normalized toNumber.MAX_SAFE_INTEGER
automatically.) - Skip must be < Number.MAX_SAFE_INTEGER
Criteria dictionaries with a mixed where
clause are no longer supported. For example, instead of:
{
username: 'santaclaus',
limit: 4,
select: ['beardLength', 'lat', 'long']
}
you should use:
{
where: { username: 'santaclaus' },
limit: 4,
select: ['beardLength', 'lat', 'long']
}
Note that you can still do
{ username: 'santaclaus' }
as shorthand for{ where: { username: 'santaclaus' } }
, you just can't mix other top-level criteria clauses (likelimit
) alongside constraints (e.g.username
).For places where you're using Waterline's chainable deferred object to build criteria, don't worry about this—it's already taken care of for you.
New apps created with Sails 1.0 will contain a config/security.js file instead of individual config/cors.js and config/csrf.js files. Apps migrating from earlier versions can keep their existing files, as long as they perform the following upgrades:
- Change
module.exports.cors
tomodule.exports.security.cors
inconfig/cors.js
- Change CORS config settings names to match the newly documented names in Reference > Configuration > sails.config.security
- Change
module.exports.csrf
tomodule.exports.security.csrf
inconfig/csrf.js
. This value is now simplytrue
orfalse
; no other CSRF options are supported (see below). sails.config.csrf.routesDisabled
is no longer supported. Instead, addcsrf: false
to any route inconfig/routes.js
that you wish to be unprotected by CSRF, for example:
'POST /some-thing': { action: 'do-a-thing', csrf: false },
sails.config.csrf.origin
is no longer supported. Instead, you can add any custom CORS settings directly to your CSRF token route configuration, for example:
'GET /csrfToken': {
action: 'security/grant-csrf-token',
cors: {
allowOrigins: ['http://foobar.com', 'https://owlhoot.com']
}
}
sails.config.csrf.grantTokenViaAjax
is no longer supported. This setting was used to turn the CSRF token-granting route on or off. In Sails 1.0, you add that route manually in yourconfig/routes.js
file (see above). If you don’t want to grant CSRF tokens via AJAX, just leave that route out ofconfig/routes.js
.
For maximum flexibility, Consolidate is no longer bundled with Sails. If you are using a view engine besides EJS, you'll probably want to install Consolidate as a direct dependency of your app. You can then configure the view engine in config/views.js
, like so:
extension: 'swig',
getRenderFn: function() {
// Import `consolidate`.
var cons = require('consolidate');
// Return the rendering function for Swig.
return cons.swig;
}
Adding custom configuration to your view engine is a lot easier in Sails 1.0:
extension: 'swig',
getRenderFn: function() {
// Import `consolidate`.
var cons = require('consolidate');
// Import `swig`.
var swig = require('swig');
// Configure `swig`.
swig.setDefaults({tagControls: ['{?', '?}']});
// Set the module that Consolidate uses for Swig.
cons.requires.swig = swig;
// Return the rendering function for Swig.
return cons.swig;
}
Note that the built-in support for layouts still works for the default EJS views, but layout support for other view engines (e.g. Handlebars or Ractive) is not bundled with Sails 1.0.
- Removed deprecated
backwardsCompatibilityFor0.9SocketClients
setting. - Removed deprecated
.subscribers()
method. - Removed deprecated "firehose" functionality.
- Removed support for 0.9.x socket client API.
- The following resourceful pubsub methods have also been removed:
.publishAdd()
.publishCreate()
.publishDestroy()
.publishRemove()
.publishUpdate()
.watch()
.unwatch()
.message()
In place of the removed methods, you should use the new .publish()
method, or the low-level sails.sockets methods. Keep in mind that unlike .message()
, .publish()
does not wrap your data in an envelope containing the record ID, so—if it's important—you'll need to include the ID yourself as part of the data. For example, in Sails v0.12.x, User.message(123, {owl: 'hoot'})
would have resulted in the following notification being broadcasted to clients:
{
verb: 'messaged',
id: 123,
data: {
owl: 'hoot'
}
}
By contrast, in Sails v1.0, User.publish(123, {owl: 'hoot'})
will simply broadcast:
{
owl: 'hoot'
}
Out of the box, it is no longer possible to add a file to api/blueprints/
that will automatically be used as a blueprint action for all models. However, this behavior can easily be replicated by installing sails-hook-custom-blueprints
.
Sails 1.0 comes with an update to the internal Express server from version 3 to version 4 (thanks to some great work by @josebaseba). This change is mainly about maintainability for the Sails framework and should be transparent to your app. However, there are a couple of differences worth noting:
- The
404
,500
andstartRequestTimer
middleware are now built-in to every Sails app, and have been removed from thesails.config.http.middleware.order
array. If your app has an overridden404
or500
handler, you should instead overrideapi/responses/notFound.js
andapi/responses/serverError.js
respectively. - Session middleware that was designed specifically for Express 3 (e.g. very old versions of
connect-redis
orconnect-mongo
) will no longer work, so you’ll need to upgrade to more recent versions. - The
sails.config.http.customMiddleware
feature is deprecated in Sails 1.0. It will still work for now, but may be removed in a later release. Instead of usingcustomMiddleware
to modify the Express app directly, use regular (req
,res
,next
) middleware instead. For instance, you can replace something like:
customMiddleware: function(app) {
var passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
}
with something like:
var passport = require('passport');
middleware: {
passportInit: passport.initialize(),
passportSession: passport.session()
},
being sure to insert passportInit
and passportSession
into your middleware.order
array in config/http.js
.
.jsonx()
is deprecated. If you have files inapi/responses
that you haven't customized at all, you can just delete them and let the Sails default responses work their magic. If you have files inapi/responses
that you’d like to keep, replace any occurences ofres.jsonx()
in those files withres.json()
.res.negotiate()
is deprecated. Useres.serverError()
,res.badRequest()
, or a custom response instead.
Sails 1.0 switches from using the i18n to the lighter-weight i18n-2 module. The overwhelming majority of users should see no difference in their apps. However, if you’re using the sails.config.i18n.updateFiles
option, be aware that this is no longer supported; instead, locale files will always be updated in development mode, and never in production mode. If this is a problem or you’re missing some other feature from the i18n module, you can install sails-hook-i18n to revert to pre-Sails-1.0 functionality.
If your 0.12 application is running into issues during upgrade due to its use of i18n features, see #4343 for more troubleshooting tips.
All Sails 1.0 projects that use websockets must install the latest sails-hook-sockets
dependency (npm install --save sails-hook-sockets
). This version of sails-hook-sockets
differs from previous ones in a couple of ways:
- The default
transports
setting is simply['websocket']
. In the majority of production deployments, restricting your app to thewebsocket
transport (rather than using['polling', 'websocket']
) avoids problems with sessions (see the pre-1.0 scaling guide notes for details). If you’re using thesails.io.js
websocket client, the easiest way to make your app compatible with the new websocket settings is to install the newsails.io.js
version withsails generate sails.io.js
. The latest version of that package also defaults to the “websocket-only” transport strategy. If you’ve customized thetransports
setting in your front-end code andconfig/sockets.js
file, then you'll just need to continue to ensure that the values in both places match. - The latest
sails-hook-sockets
hook uses a newer version of Socket.io. See the Socket.io changelog for a full update, but keep in mind that socket IDs no longer have/#
prepended to them by default.
The Grunt task-management functionality that was formerly part of the Sails core has now been moved into the separate sails-hook-grunt
module. Existing apps simply need to npm install --save sails-hook-grunt
to continue using Grunt. However, with a modification to your app’s Gruntfile.js
, you can take advantage of the fact that sails-hook-grunt
includes all of the grunt-contrib
modules that previously had to be installed at the project level. The new Gruntfile.js
contains:
module.exports = function(grunt) {
var loadGruntTasks = require('sails-hook-grunt/accessible/load-grunt-tasks');
// Load Grunt task configurations (from `tasks/config/`) and Grunt
// task registrations (from `tasks/register/`).
loadGruntTasks(__dirname, grunt);
};
Assuming that you haven’t customized the Gruntfile in your app, you can replace Gruntfile.js
with that code and then safely run:
npm uninstall --save grunt-contrib-clean
npm uninstall --save grunt-contrib-coffee
npm uninstall --save grunt-contrib-concat
npm uninstall --save grunt-contrib-copy
npm uninstall --save grunt-contrib-cssmin
npm uninstall --save grunt-contrib-jst
npm uninstall --save grunt-contrib-less
npm uninstall --save grunt-contrib-uglify
npm uninstall --save grunt-contrib-watch
npm uninstall --save grunt-sails-linker
npm uninstall --save grunt-sync
npm uninstall --save grunt-cli
to remove those dependencies from your project.
Make sure you have sails
installed locally in your project, and that you're using the v1 version of the command-line tool.
To install the v1.0 globally, run npm install sails@^1.0.0 -g
. To install it for a particular Sails app, cd into that app's directory, then run npm install sails@^1.0.0 --save
. (After installing locally, be sure to also install the necessary hooks -- see above.)