Required Relation Field

hi @hunter

can you just help me to how to implement this service in my case beacuse i’m facing same issue for required true

i have no custom controller & no custom service till now
then how would i integrate this service

My files Code ::
service/project.js

'use strict';

/**
 * project service
 */

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::project.project');

controller/project.js

'use strict';

/**
 * project controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::project.project');

and the last one schema.json

{
  "kind": "collectionType",
  "collectionName": "projects",
  "info": {
    "singularName": "project",
    "pluralName": "projects",
    "displayName": "Project",
    "description": ""
  },
  "options": {
    "draftAndPublish": true
  },
  "pluginOptions": {},
  "attributes": {
    "title": {
      "type": "string",
      "required": true
    },
    "description": {
      "type": "richtext",
      "required": true
    },
    "projectMediumCategory": {
      "type": "relation",
      "relation": "oneToOne",
      "target": "api::medium-category.medium-category",
      "required": true
    },
    "projectSubjectMatterCategories": {
      "type": "relation",
      "relation": "oneToMany",
      "target": "api::subject-matter-category.subject-matter-category",
      "required": true
    }
  }
}

This issue only occurred for oneToMany relation keep in Mind Guy’s

Please help me ! @hunter

1 Like

Have the same question
up to 4.4.5 no effect

Hi @hunter,

checking the publishedAt property works perfectly if you’re publishing, but what about un-publish? In that case, publishedAt is also null.

Is there any other way to check how beforeUpdate was invoked?

Best regards,
Tom

For me, the undocumented feature of simply setting required: true worked up until 4.5.0 where https://github.com/strapi/strapi/pull/14401/ was released.

With that PR the content manager started submitting more complex object as the value for relations fields even if the value is empty. Unfortunately, this object passes through the required validator as it merely checks the value isn’t null or undefined.

BTW, if you implemented this check manually in your controllers and you really need to enforce this invariant you should consider if your check handles this new syntax. It goes roughly like this:

relation_attribute: { 
  connect: [<ids to attach>],
  disconnect: [<ids to detach>)
}

Note that this syntax is “procedural” - it doesn’t state what the resulting data should be, but rather describes how to achieve the desired state by a set of updates. This makes a robust required check quite hard to pull-off as you’d have to first pull the current state of the entity from the DB, run the proposed updates, and only then check if the result is empty or not. If you think that embedding a procedural syntax inside a REST API is unfortunate well, you’re not alone. :man_shrugging:

2 Likes

You can follow the progress in the feature request: Specify relation column as required | Content Editing XP | Strapi I can’t give you an estimate, but we are currently exploring adding this option to relational fields and will notify you through the feature request.

2 Likes

thanks this worked as charm, just going to the schema and add anoer required manually, thanska a lot x)

Posting a solution for strapi versions above 4.5.0

To check if relation field is filled every time you change it you have to:
“check strapi data” - I check strapi data by doing this:
It goes through array of fields to “check” and it returns the field value if field was changed or false

function checkField(data, fieldName) {
  const field = data[fieldName]
  return { [fieldName]: field.connect.length > 0 && { id: field.connect[0].id}  }
}

function checkContentData(data, fieldsArray) {
  const checkedData = fieldsArray.reduce((result, field) => {
    result[field] = checkField(data, field)[field];
    return result;
  }, {});
  return {
    ...data,
    ...checkedData
  }
}

and use it in lifecycles while passing an array of relation fields I want to check
so:

const checkedData = checkContentData(data, ['field_name', 'field_name_2'])

This gets you a connect value, you only use disconnect in if statements below

in if statement you must use the data from
const { data } = event.params;
but in your validation logic you pass in checkedData, because you only validate it if it was disconnected

This is used in beforeUpdate lifecycle:

if(data.field_name.disconnect.length === 1 && data.field_name.connect.length === 0) {
  if(!checkedData.field_name) {
    throw new ForbiddenError('relation field is empty)
  }
}

This is used in beforeCreate:
because if it wasn’t touched then you know it’s empty

if(data.field_name.disconnect.length === 0 && data.field_name.connect.length === 0) {
  if(!checkedData.field_name) {
    throw new ForbiddenError('relation field is empty)
  }
}

This is such an important feature and it’s not implemented. Incredible.

To be specific, in Strapi 4.16.2 (the latest version at the time of writing this), adding the required: true to the relation attribute still does not prevent the creation of the entry in the interface, although the relation field has a red asterisk close to it, like normal required attributes have. This is strange because Strapi automatically updates the types once we do this. So, clearly, there’s a bug in Strapi, which has been around for so many versions and years, and the developers don’t seem to care. Moreover, in the interface, we cannot set this relation attribute to be required, like for normal attributes.

1 Like

Yes. I am having the same issue.

Did you check Strapi 5?