Merge branch 'master' into patch-1

This commit is contained in:
Jim LAURIE 2019-10-29 21:19:07 +01:00 committed by GitHub
commit 8ba1c1f51a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 248 additions and 261 deletions

View File

@ -156,7 +156,7 @@ Before submitting an issue you need to make sure:
- You have tried all the following (if relevant) and your issue remains:
- Make sure you have the right application started.
- Make sure the [issue template](.github/ISSUE_TEMPLATE) is respected.
- Make sure your issue body is readable and [well formated](https://guides.github.com/features/mastering-markdown).
- Make sure your issue body is readable and [well formatted](https://guides.github.com/features/mastering-markdown).
- Make sure you've killed the Strapi server with CTRL+C and started it again.
- Make sure the application you are using to reproduce the issue has a clean `node_modules` directory, meaning:
- no dependencies are linked (e.g. you haven't run `npm link`)

View File

@ -124,10 +124,12 @@ module.exports = {
collapsable: true,
title: '📚 Guides',
children: [
'/3.0.0-beta.x/guides/update-version',
'/3.0.0-beta.x/guides/databases',
'/3.0.0-beta.x/guides/deployment',
'/3.0.0-beta.x/guides/jwt-validation',
'/3.0.0-beta.x/guides/error-catching',
'/3.0.0-beta.x/guides/slug',
'/3.0.0-beta.x/guides/webhooks',
],
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -66,7 +66,7 @@ Here are some use cases:
- Create an admin user if there isn't one.
- Fill the database with some necessary data.
- Check that the database is up-and-running.
- Load some envrionments variables.
- Load some environments variables.
The bootstrap function can be synchronous or asynchronous

View File

@ -4,48 +4,50 @@
Models are a representation of the database's structure and lifecycle. They are split into two separate files. A JavaScript file that contains the lifecycle callbacks, and a JSON one that represents the data stored in the database and their format. The models also allow you to define the relationships between them.
**Path —** `./api/user/models/User.js`.
**Path —** `./api/restaurant/models/Restaurant.js`.
```js
module.exports = {
// Before saving a value.
// Fired before an `insert` or `update` query.
beforeSave: next => {
// Use `this` to get your current object
next();
},
beforeSave: (model, attrs, options) => {},
// After saving a value.
// Fired after an `insert` or `update` query.
afterSave: (doc, next) => {
next();
},
afterSave: (model, attrs, options) => {},
// ... and more
};
```
**Path —** `./api/user/models/User.settings.json`.
**Path —** `./api/restaurant/models/Restaurant.settings.json`.
```json
{
"connection": "default",
"info": {
"name": "user",
"description": "This represents the User Model"
"name": "restaurant",
"description": "This represents the Restaurant Model"
},
"attributes": {
"firstname": {
"cover": {
"collection": "file",
"via": "related",
"plugin": "upload"
},
"name": {
"default": "",
"type": "string"
},
"lastname": {
"type": "string"
"description": {
"default": "",
"type": "text"
}
}
}
```
In this example, there is a `User` model which contains two attributes `firstname` and `lastname`.
In this example, there is a `Restaurant` model which contains two attributes `cover`, `name` and `description`.
### Where are the models defined?
@ -57,12 +59,12 @@ The models are defined in each `./api/**/models/` folder. Every JavaScript or JS
If you are just starting out it is very convenient to generate some models with the Content Type Builder, directly in the admin interface. You can then review the generated model mappings on the code level. The UI takes over a lot of validation tasks and gives you a fast feeling for available features.
:::
Use the CLI, and run the following command `strapi generate:model user firstname:string lastname:string`. Read the [CLI documentation](../cli/CLI.md) for more information.
Use the CLI, and run the following command `strapi generate:model restaurant name:string description:text`. Read the [CLI documentation](../cli/CLI.md) for more information.
This will create two files located at `./api/user/models`:
This will create two files located at `./api/restaurant/models`:
- `User.settings.json`: contains the list of attributes and settings. The JSON format makes the file easily editable.
- `User.js`: imports `User.settings.json` and extends it with additional settings and lifecycle callbacks.
- `Restaurant.settings.json`: contains the list of attributes and settings. The JSON format makes the file easily editable.
- `Restaurant.js`: imports `Restaurant.settings.json` and extends it with additional settings and lifecycle callbacks.
::: note
when you create a new API using the CLI (`strapi generate:api <name>`), a model is automatically created.
@ -76,18 +78,18 @@ Additional settings can be set on models:
- `collectionName` (string) - Collection's name (or table's name) in which the data should be stored.
- `globalId` (string) -Global variable name for this model (case-sensitive).
**Path —** `User.settings.json`.
**Path —** `Restaurant.settings.json`.
```json
{
"connection": "mongo",
"collectionName": "Users_v1",
"globalId": "Users",
"collectionName": "Restaurants_v1",
"globalId": "Restaurants",
"attributes": {}
}
```
In this example, the model `User` will be accessible through the `Users` global variable. The data will be stored in the `Users_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
In this example, the model `Restaurant` will be accessible through the `Restaurants` global variable. The data will be stored in the `Restaurants_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
::: note
The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.
@ -101,12 +103,12 @@ The info key on the model-json states information about the model. This informat
- `description`: The description of the model.
- `mainField`: Determines which model-attribute is shown when displaying the model.
**Path —** `User.settings.json`.
**Path —** `Restaurant.settings.json`.
```json
{
"info": {
"name": "user",
"name": "restaurant",
"description": ""
}
}
@ -137,6 +139,7 @@ The following types are currently available:
- `string`
- `text`
- `richtext`
- `integer`
- `biginteger`
- `float`
@ -172,45 +175,24 @@ To improve the Developer eXperience when developing or using the administration
### Example
**Path —** `User.settings.json`.
**Path —** `Restaurant.settings.json`.
```json
{
"connection": "default",
"info": {
"name": "user",
"description": "This represents the User Model",
"mainField": "email"
},
...
"attributes": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"email": {
"type": "email",
"required": true,
"title": {
"type": "string",
"min": 3,
"max": 99,
"unique": true
},
"password": {
"type": "password",
"required": true,
"private": true
"description": {
"default": "My descrioption",
"type": "text",
"required": true
},
"about": {
"type": "description"
},
"age": {
"type": "integer",
"min": 18,
"max": 99,
"index": true
},
"birthday": {
"type": "date"
}
...
}
}
```
@ -243,21 +225,6 @@ A `pet` can be owned by someone (a `user`).
}
```
**Path —** `./api/pet/controllers/Pet.js`.
```js
// Mongoose example
module.exports = {
findPetsWithOwners: async ctx => {
// Retrieve the list of pets with their owners.
const pets = Pet.find().populate('owner');
// Send the list of pets.
ctx.body = pets;
},
};
```
**Example**
```js
@ -309,36 +276,6 @@ A `user` can have one `address`. And this address is only related to this `user`
}
```
**Path —** `./api/user/controllers/User.js`.
```js
// Mongoose example
module.exports = {
findUsersWithAddresses: async ctx => {
// Retrieve the list of users with their addresses.
const users = User.find().populate('address');
// Send the list of users.
ctx.body = users;
},
};
```
**Path —** `./api/adress/controllers/Address.js`.
```js
// Mongoose example
module.exports = {
findArticlesWithUsers: async ctx => {
// Retrieve the list of addresses with their users.
const articles = Address.find().populate('user');
// Send the list of addresses.
ctx.body = addresses;
},
};
```
**Example**
```js
@ -390,36 +327,6 @@ A `user` can have many `articles`, and an `article` can be related to one `user`
}
```
**Path —** `./api/user/controllers/User.js`.
```js
// Mongoose example
module.exports = {
findUsersWithArticles: async ctx => {
// Retrieve the list of users with their articles.
const users = User.find().populate('articles');
// Send the list of users.
ctx.body = users;
},
};
```
**Path —** `./api/article/controllers/Article.js`.
```js
// Mongoose example
module.exports = {
findArticlesWithAuthors: async ctx => {
// Retrieve the list of articles with their authors.
const articles = Article.find().populate('author');
// Send the list of users.
ctx.body = articles;
},
};
```
**Examples**
```js
@ -486,36 +393,6 @@ A `product` can be related to many `categories`, so a `category` can have many `
}
```
**Path —** `./api/product/controllers/Product.js`.
```js
// Mongoose example
module.exports = {
findProductsWithCategories: async ctx => {
// Retrieve the list of products.
const products = Product.find().populate('categories');
// Send the list of products.
ctx.body = products;
},
};
```
**Path —** `./api/category/controllers/Category.js`.
```js
// Mongoose example
module.exports = {
findCategoriesWithProducts: async ctx => {
// Retrieve the list of categories.
const categories = Category.find().populate('products');
// Send the list of categories.
ctx.body = categories;
},
};
```
**Example**
```js
@ -644,102 +521,6 @@ A `Image` model might belongs to many either `Article` models or a `Product` mod
}
```
**Path —** `./api/image/controllers/Image.js`.
```js
// Mongoose example
module.exports = {
findFiles: async ctx => {
// Retrieve the list of images with the Article or Product entries related to them.
const images = Images.find().populate('related');
/*
[{
"_id": "5a81b0fa8c063a53298a934a",
"url": "http://....",
"name": "john_doe_avatar.png",
"related": [{
"_id": "5a81b0fa8c063a5393qj934a",
"title": "John Doe is awesome",
"description": "..."
}, {
"_id": "5a81jei389ns5abd75f79c",
"name": "A simple chair",
"description": "..."
}]
}]
*/
// Send the list of files.
ctx.body = images;
},
};
```
**Path —** `./api/article/controllers/Article.js`.
```js
// Mongoose example
module.exports = {
findArticlesWithAvatar: async ctx => {
// Retrieve the list of articles with the avatar (image).
const articles = Article.find().populate('avatar');
/*
[{
"_id": "5a81b0fa8c063a5393qj934a",
"title": "John Doe is awesome",
"description": "...",
"avatar": {
"_id": "5a81b0fa8c063a53298a934a",
"url": "http://....",
"name": "john_doe_avatar.png"
}
}]
*/
// Send the list of users.
ctx.body = articles;
},
};
```
**Path —** `./api/product/controllers/Product.js`.
```js
// Mongoose example
module.exports = {
findProductWithPictures: async ctx => {
// Retrieve the list of products with the pictures (images).
const products = Product.find().populate('pictures');
/*
[{
"_id": "5a81jei389ns5abd75f79c",
"name": "A simple chair",
"description": "...",
"pictures": [{
"_id": "5a81b0fa8c063a53298a934a",
"url": "http://....",
"name": "chair_position_1.png"
}, {
"_id": "5a81d22bee1ad45abd75f79c",
"url": "http://....",
"name": "chair_position_2.png"
}, {
"_id": "5a81d232ee1ad45abd75f79e",
"url": "http://....",
"name": "chair_position_3.png"
}]
}]
*/
// Send the list of users.
ctx.body = products;
},
};
```
#### Database implementation
If you're using MongoDB as a database, you don't need to do anything. Everything is natively handled by Strapi. However, to implement a polymorphic relationship with SQL databases, you need to create two tables.
@ -811,7 +592,7 @@ CREATE TABLE `image_morph` (
::: warning
The life cycle functions are based on the ORM life cycle and not on the strapi request.
We are currently woking on it to make it easier to use and understand.
We are currently working on it to make it easier to use and understand.
Please check [this issue](https://github.com/strapi/strapi/issues/1443) on GitHub.
:::

View File

@ -0,0 +1,107 @@
# Create a slug system
This guide will explain how to create a slug system for a Post, Article or any Content Type you want.
## Create attributes
To start building your slug system you need a `string` field as a **base** for your slug, in this example we will use `title`.
You will also need another `string` field that contains the slugified value of your `title`, in this case we will use `slug`.
![Slug fields](../assets/guides/slug/fields.png)
## Configure the layout for the content editor
Let's configure the layout of the **edit page** to make it more user friendly for the content editor.
- Click on the **Content Manager** link in the left menu.
- Then on the `Article` Content Type.
- And finally on the **Edit View** tab.
Here we will be able to setup the `slug` field.
- Click on the `slug` field.
- At the bottom of the page, edit the **placeholder** value to `Generated automatically based on the title`.
- And click **OFF** for **Editable field** option.
- Don't forget to save your updates.
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Edit View before" id="before"
![Edit View before](../assets/guides/slug/layout-before.png)
:::
::: tab "Edit View after" id="after"
![Edit View after](../assets/guides/slug/layout-after.png)
:::
::: tab "Edit View configuration" id="config"
![Edit View config](../assets/guides/slug/layout-config.png)
:::
::::
## Auto create/update the `slug` attribute
For that you will have to install `slugify` node module in your application.
When it's done, you have to update the life cycle of the **Article** Content Type to auto complete the `slug` field.
**Path —** `./api/article/models/Article.js`
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Mongoose" id="mongoose"
```js
const slugify = require('slugify');
module.exports = {
beforeSave: async model => {
if (model.title) {
model.slug = slugify(model.title);
}
},
beforeUpdate: async model => {
if (model.getUpdate().title) {
model.update({
slug: slugify(model.getUpdate().title),
});
}
},
};
```
:::
::: tab "Bookshelf" id="bookshelf"
```js
const slugify = require('slugify');
module.exports = {
beforeSave: async (model, attrs, options) => {
if (options.method === 'insert' && attrs.title) {
model.set('slug', slugify(attrs.title));
} else if (options.method === 'update' && attrs.title) {
attrs.slug = slugify(attrs.title);
}
}
}
:::
::::
## Fetch article by `slug`
Then you will have to be able to fetch your **Articles** by this slug.
You will be able to find your articles by slug with this request `GET /articles?slug=my-article-slug`
```

View File

@ -0,0 +1,97 @@
# Update Strapi version
How to upgrade your application to the latest version of Strapi.
## Upgrading your dependencies
Start by upgrading all your strapi package version.
For example moving from `3.0.0-beta.16` to `3.0.0-beta.17`
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Before - 3.0.0-beta.16" id="3.0.0-beta.16"
```json
{
//...
"dependencies": {
"strapi": "3.0.0-beta.16",
"strapi-admin": "3.0.0-beta.16",
"strapi-hook-bookshelf": "3.0.0-beta.16",
"strapi-hook-knex": "3.0.0-beta.16",
"strapi-plugin-content-manager": "3.0.0-beta.16",
"strapi-plugin-content-type-builder": "3.0.0-beta.16",
"strapi-plugin-email": "3.0.0-beta.16",
"strapi-plugin-graphql": "3.0.0-beta.16",
"strapi-plugin-settings-manager": "3.0.0-beta.16",
"strapi-plugin-upload": "3.0.0-beta.16",
"strapi-plugin-users-permissions": "3.0.0-beta.16",
"strapi-utils": "3.0.0-beta.16"
}
}
```
:::
::: tab "After - 3.0.0-beta.17" id="3.0.0-beta.17"
```json
{
//...
"dependencies": {
"strapi": "3.0.0-beta.17",
"strapi-admin": "3.0.0-beta.17",
"strapi-hook-bookshelf": "3.0.0-beta.17",
"strapi-hook-knex": "3.0.0-beta.17",
"strapi-plugin-content-manager": "3.0.0-beta.17",
"strapi-plugin-content-type-builder": "3.0.0-beta.17",
"strapi-plugin-email": "3.0.0-beta.17",
"strapi-plugin-graphql": "3.0.0-beta.17",
"strapi-plugin-settings-manager": "3.0.0-beta.17",
"strapi-plugin-upload": "3.0.0-beta.17",
"strapi-plugin-users-permissions": "3.0.0-beta.17",
"strapi-utils": "3.0.0-beta.17"
}
}
```
:::
::::
Then run either `yarn install` or `npm install` to install the specified version.
::: note
If the operation doesn't work, you should probably remove your `yarn.lock` or `package-lock.json`. And if it still not work let's run the hard mode `rm -Rf node_modules`
:::
## Building your administration panel
New release can introduces changes to the administration panel that require a rebuild.
Start by deleting your current build:
```bash
rm -rf build
```
Build the administration panel:
```bash
yarn build
# or
npm run build
```
::: note
If the operation doesn't work, you should probably remove the `.cache` folder too.
:::
## Migration guides
Sometimes Strapi introduces changes that need more than just the previous updates.
That is the reason of the [Migration Guide](../migration-guide/README.md) page.
Just make sure when you update your version that a migration guide exist or not.