Save more than one entity

Hello everyone,

I have one question: I am trying to find a way to add recurrent event in Forest Admin. For now, I managed to create a table “Appointment” in which I can choose a startDate and an endDate. I would like to add a recurrence to this such as “Every Week”, “Every Month” etc …

In order to do that, I need to be able to save more than one entity when I press “Create”, is it possible ?

Thank you :slight_smile:

Hello @clementbernardo

Thank you for you feedback.
Unfortunately there is no builtin “bulk create” in ForestAdmin for now. I’ll share your input with the product team.

For now, I can offer two leads on how to implement this.

First, you can override the create route for your collection, and depending on the payload, you can directly call the create method of your model accordingly.
Please have a look at how to override a route here.

You can also try to add a global SmartAction to your collection, and using a SmartAction Form you can send any parameter (startDate, endDate, recurrence, title…) and create all the records you need.

Please let me know if this helps.

Hello Guillaume,

Thank you for your answer. I will try to implement this tomorrow and i’ll tell if it works. Thanks a lot !

Hi Guillaume, how are you ?

I tried to implement the route you mentioned in order to make recurrent event creation. i am getting an error a bit odd and I cannot find on the internet why I am getting it.

FYI my route is defined as this:

router.post(
  '/appointments',
  permissionMiddlewareCreator.create(),
  async (request, response, next) => {
    let appointmentRequest = request;

    const appointmentFrequency = request.body.data.attributes.appointmentFrequency;

    if (appointmentFrequency === 'none') {
      await createAnAppointment(request, response, next);
      next();
    } else if (appointmentFrequency === 'daily') {
      for (let i = 0; i < NUMBER_OF_DAYS_IN_A_YEAR; i++) {
        await createAnAppointment(appointmentRequest, response, next);
        appointmentRequest.body.data.attributes.startDate = await addADayDurationToDate(
          appointmentRequest.body.data.attributes.startDate,
        );
        appointmentRequest.body.data.attributes.endDate = await addADayDurationToDate(
          appointmentRequest.body.data.attributes.endDate,
        );
      }
      next();
    } else {
      for (let i = 0; i < NUMBER_OF_WEEKS_IN_A_YEAR; i++) {
        await createAnAppointment(appointmentRequest, response, next);
        appointmentRequest.body.data.attributes.startDate = addAWeekDurationToDate(
          appointmentRequest.body.data.attributes.startDate,
        );
        appointmentRequest.body.data.attributes.endDate = addAWeekDurationToDate(
          appointmentRequest.body.data.attributes.endDate,
        );
      }
    }
    next();
  },
);

with:


export const createAnAppointment = async (request, response, next) => {
  const { body, query, user } = request;
  const recordCreator = new RecordCreator(appointments, user, query);

  const recordToCreate = await recordCreator.deserialize(body);
  const recordCreated = await recordCreator.create(recordToCreate);
  const recordSerialized = await recordCreator.serialize(recordCreated);

  await response.send(recordSerialized);
};

Hello @clementbernardo,

From reading the code, I think there is an issue with the way you are mixing async/await and response.send (via createAnAppointment).

First, response.send is allowed only once per request (it will call response.end when done).
Second, using await within a for loop can be tricky.

May I suggest something like:

// => only using the request
export const createAnAppointment = async (request) => {
  const { body, query, user } = request;
  const recordCreator = new RecordCreator(appointments, user, query);

  const recordToCreate = await recordCreator.deserialize(body);
  const recordCreated = await recordCreator.create(recordToCreate);

  // => directly return the new, unserialised, record
  return recordCreated;
};

and:

router.post(
  '/appointments',
  permissionMiddlewareCreator.create(),
  async (request, response, next) => {
    // => store all record creation promises
    const recordPromises = [];

    let appointmentRequest = request;

    const appointmentFrequency = request.body.data.attributes.appointmentFrequency;

    // => push all requests while incrementing startDate/endDate as needed
    if (appointmentFrequency === 'none') {
      recordPromises.push(createAnAppointment(request);
    } else if (appointmentFrequency === 'daily') {
      let { endDate, startDate } = appointmentRequest.body.data.attributes;
      for (let i = 0; i < NUMBER_OF_DAYS_IN_A_YEAR; i++) {
        recordPromises.push(createAnAppointment(appointmentRequest);
        startDate = await addADayDurationToDate(startDate);
        endDate = await addADayDurationToDate(endDate);
      }
    } else {
      let { endDate, startDate } = appointmentRequest.body.data.attributes;
      for (let i = 0; i < NUMBER_OF_WEEKS_IN_A_YEAR; i++) {
        recordPromises.push(createAnAppointment(appointmentRequest);
        startDate = await addAWeekDurationToDate(startDate);
        endDate = await addAWeekDurationToDate(endDate);
      }
    }

    // => wait for all records to be created, then serialise and send
    const recordsCreated = await Promise.all(recordPromises);
    const recordCreator = new RecordCreator(appointments, user, query);
    const recordsSerialized = await recordCreator.serialize(recordsCreated);
    response.send(recordsSerialized);
  },
);

This code was not tested, but it should go in the right direction.

Let me know if this helps.

1 Like