Я пытаюсь управлять двумя связанными ресурсами в одном 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>
);