Добавить / изменить несколько ресурсов в одной форме - PullRequest
1 голос
/ 28 марта 2020

Я пытаюсь управлять двумя связанными ресурсами в одном Edit> SimpleForm. Соотношение между двумя ресурсами взаимно однозначно между двумя таблицами.

Например, предположим, у нас есть две таблицы:

Пользователь

  • id
  • электронная почта
  • пароль
  • имя
  • address_id

Адрес

  • id
  • улица
  • номер
  • почтовый индекс
  • страна_имя

Я используюact-admin для управления записями из этих двух таблиц из PostgreSQL через graphql (используя hasura ). Есть несколько вариантов с точки зрения поставщика данных для hasura и graphql.

Первый, который я попробовал ra-data-hasura , работает с использованием конечной точки API REST /v1/query hasura. Документация для этой конечной точки отсутствует.

Я также пытался ra-data-graphql-simple и ra-data-hasura-graphql .

Насколько я могу судить, никто не поддерживает запросы к таблицам отношений / внешних ключей в одном запросе. Поэтому ни один из этих провайдеров не может извлечь таблицы внешних ключей и встроить результат непосредственно в ответ основного объекта json.

Просто чтобы прояснить, я имею в виду возвращать что-то подобное для пользователя:

{
 "id": 1,
 "name": "John Smith",
 "email": "john.smith@gmail.com",
 "password": "password",
 "address": {
   "id": 145,
   "street": "High Street",
   "number": "25b",
   "postcode": "EC2 5FG",
   "country_name": "United Kingdom"
 }
}

Поэтому я пытаюсь получить запись address в форме Edit, используя отдельный запрос , что я и сделал (вероятно, не лучшим образом, не стесняйтесь предложить лучшую версию):

import { useGetOne, Loading, Error } from 'react-admin';

const FetchRelated = ({ record, reference, source, children }) => {
    const { data, loading, error } = useGetOne(reference, record[source]);
    if (loading) return <Loading />;
    if (error) return <Error />;
    if (!data) return null;

    // this is the only way I found to be able to populate the fields in the form with the address data
    record[reference] = data;

    return <React.Fragment>{children}</React.Fragment>;
};

...
import { Edit, SimpleForm, TextInput } from 'react-admin';

...
const UserEdit = props => (
 <Edit {...props}>
  <SimpleForm>
   <FetchRelated reference="address" source="address_id">
    <TextInput source="address.postcode" label="Post Code" />
   </FetchRelated>
  </SimpleForm>
 </Edit>
);

Используя это, мой record объект теперь выглядит так:

{
 "id": 1,
 "name": "John Smith",
 "email": "john.smith@gmail.com",
 "password": "password",
 "address_id": 145,
 "address": {
   "id": 145,
   "street": "High Street",
   "number": "25b",
   "postcode": "EC2 5FG",
   "country_name": "United Kingdom"
 }
}

Теперь я должен позаботиться о реальном запросе на редактирование. Кажется, react-admin использует useEditController для всех запросов запуска (как useGetOne и update). В то время как метод обновления передается как save атрибут SimpleForm, он не передается Toolbar, что означает (из того, что я могу сказать), никто не может переопределить handleSubmit / handleSubmitWithRedirect реквизитов SaveButton без необходимости по существу копировать весь код для update из useEditController.

В идеале, можно переопределить handleSubmit и сделать один update для обоих ресурсов одновременно. Использование мутации graphql не вызовет особых проблем, к сожалению, использование конечной точки hasura /v1/graphql не дает возможности обновить отношения в одном запросе. Поэтому нам нужно выполнить два запроса, и это нормально.

В идеале я хотел бы повторно использовать существующий метод update для обновления записи user и добавить еще один вызов для обновления address ,

Каков наилучший из возможных подходов для достижения чего-то подобного?

import React, { useCallback } from 'react';
import { useForm } from 'react-final-form';
import { useSelector } from 'react-redux';
import { Toolbar, SaveButton, DeleteButton, useMutation } from 'react-admin';

const RelatedSaveButton = ({ resourceName, id, handleSubmitWithRedirect, ...props }) => {
  const form = useForm();
  const stateData = useSelector(
        state =>
             state.admin.resources[resourceName]
                 ? state.admin.resources[resourceName].data
                 : null,
         [resourceName]
     );
  const [update] = useMutation();
  const handleSave = useCallback((values, redirect) => {
    const params = {type: 'update', resource: resourceName, payload: {id: id, data: values[resourceName], previousData: stateData}};
    update(params, {onSuccess: response => {
      // doing something here to update `user` using `save` from `useEditController`
      // handleSubmitWithRedirect(redirect);
    }});
  }, [resourceName, stateData, id, update]);

  return <SaveButton {...props} onSave={handleSave} />;
};

const UserToolbar = ({ ...props }) => (
  <Toolbar {...props}>
    <RelatedSaveButton resourceName='address' id={props.record['address_id']} />
    <DeleteButton />
  </Toolbar>
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...