Подключение admin-on-rest с Rails Api

Мне очень трудно подключить admin-on-rest к моему API-интерфейсу rails. Я следил за пошаговым руководством по адресу https://marmelab.com/admin-on-rest/Tutorial.html, но когда я указываю на свой локальный хост, начинаются все проблемы.

Ответ

{
    "events": [
        {
            "id": 13,
            "name": "Event 1",
            "description": "test"
        },
        {
            "id": 16,
            "name": "Event 2",
            "description": "dsadfa adf asd"
        },
        {
            "id": 17,
            "name": "Event 3",
            "description": "Hey this is a test"
        },
        {
            "id": 18,
            "name": "Some Stuff",
            "description": "Yay, it work"
        },
        {
            "id": 20,
            "name": "Test",
            "description": "asdfs"
        }
    ],
    "meta": {
        "current_page": 1,
        "next_page": null,
        "prev_page": null,
        "total_pages": 1,
        "total_count": 5
    }
}

App.js

import React from 'react';
import { jsonServerRestClient, fetchUtils, Admin, Resource } from 'admin-on-rest';

import apiClient from './apiClient';

import { EventList } from './events';
import { PostList } from './posts';

const httpClient = (url, options = {}) => {
  if (!options.headers) {
      options.headers = new Headers({ Accept: 'application/json' });
  }
  // add your own headers here
  // options.headers.set('X-Custom-Header', 'foobar');
  return fetchUtils.fetchJson(url, options);
}
const restClient = apiClient('http://localhost:5000/admin', httpClient);


const App = () => (
  <Admin title="My Admin" restClient={restClient}>
    <Resource name="events" list={EventList} />
  </Admin>
);

export default App;

apiClient.js

 import { stringify } from 'query-string';
    import {
  GET_LIST,
  GET_ONE,
  GET_MANY,
  GET_MANY_REFERENCE,
  CREATE,
  UPDATE,
  DELETE,
  fetchJson
} from 'admin-on-rest';

/**
 * Maps admin-on-rest queries to a simple REST API
 *
 * The REST dialect is similar to the one of FakeRest
 * @see https://github.com/marmelab/FakeRest
 * @example
 * GET_LIST     => GET http://my.api.url/posts?sort=['title','ASC']&range=[0, 24]
 * GET_ONE      => GET http://my.api.url/posts/123
 * GET_MANY     => GET http://my.api.url/posts?filter={ids:[123,456,789]}
 * UPDATE       => PUT http://my.api.url/posts/123
 * CREATE       => POST http://my.api.url/posts/123
 * DELETE       => DELETE http://my.api.url/posts/123
 */
export default (apiUrl, httpClient = fetchJson) => {
  /**
   * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
   * @param {String} resource Name of the resource to fetch, e.g. 'posts'
   * @param {Object} params The REST request params, depending on the type
   * @returns {Object} { url, options } The HTTP request parameters
   */
  const convertRESTRequestToHTTP = (type, resource, params) => {
    console.log(type)
    console.log(params)
    console.log(params.filter)
    console.log(resource)
    console.log(fetchJson)

    let url = '';
    const options = {};
    switch (type) {
      case GET_LIST: {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
          sort: JSON.stringify([field, order]),
          range: JSON.stringify([
            (page - 1) * perPage,
            page * perPage - 1,
          ]),
          filter: JSON.stringify(params.filter),
        };
        url = `${apiUrl}/${resource}?${stringify(query)}`;
        break;
      }
      case GET_ONE:
        url = `${apiUrl}/${resource}/${params.id}`;
        break;
      case GET_MANY: {
        const query = {
          filter: JSON.stringify({ id: params.ids }),
        };
        url = `${apiUrl}/${resource}?${stringify(query)}`;
        break;
      }
      case GET_MANY_REFERENCE: {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
          sort: JSON.stringify([field, order]),
          range: JSON.stringify([
            (page - 1) * perPage,
            page * perPage - 1,
          ]),
          filter: JSON.stringify({
            ...params.filter,
            [params.target]: params.id,
          }),
        };
        url = `${apiUrl}/${resource}?${stringify(query)}`;
        break;
      }
      case UPDATE:
        url = `${apiUrl}/${resource}/${params.id}`;
        options.method = 'PUT';
        options.body = JSON.stringify(params.data);
        break;
      case CREATE:
        url = `${apiUrl}/${resource}`;
        options.method = 'POST';
        options.body = JSON.stringify(params.data);
        break;
      case DELETE:
        url = `${apiUrl}/${resource}/${params.id}`;
        options.method = 'DELETE';
        break;
      default:
        throw new Error(`Unsupported fetch action type ${type}`);
    }
    return { url, options };
  };

  /**
   * @param {Object} response HTTP response from fetch()
   * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
   * @param {String} resource Name of the resource to fetch, e.g. 'posts'
   * @param {Object} params The REST request params, depending on the type
   * @returns {Object} REST response
   */
  const convertHTTPResponseToREST = (response, type, resource, params) => {
    const { headers, json } = response;
    switch (type) {
      case GET_LIST:
      case GET_MANY_REFERENCE:
        // if (!headers.has('content-range')) {
        //   throw new Error(
        //     'The Content-Range header is missing in the HTTP Response. The simple REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?'
        //   );
        // }
        console.log("DATA", json[resource])
        return {
          data: json[resource],
          total: json.meta.total_count
        };
      case CREATE:
        return { data: { ...params.data, id: json.id } };
      default:
        return { data: json };
    }
  };

  /**
   * @param {string} type Request type, e.g GET_LIST
   * @param {string} resource Resource name, e.g. "posts"
   * @param {Object} payload Request parameters. Depends on the request type
   * @returns {Promise} the Promise for a REST response
   */
  return (type, resource, params) => {
    const { url, options } = convertRESTRequestToHTTP(
      type,
      resource,
      params
    );
    return httpClient(url, options).then(response =>{
      console.log("RESPONSE", response);
      convertHTTPResponseToREST(response, type, resource, params)}
    );
  };
};

события.js

import React from 'react';
import { List, Datagrid, Edit, Create, SimpleForm, DateField, ImageField, ReferenceField, translate,
  TextField, EditButton, DisabledInput, TextInput, LongTextInput, DateInput, Show, Tab, TabbedShowLayout } from 'admin-on-rest';

export EventIcon from 'material-ui/svg-icons/action/today';
const EventTitle = translate(({ record, translate }) => (
  <span>
    {record ? translate('event.edit.name', { title: record.name }) : ''}
  </span>
));

export const EventList = (props) => (
  <List {...props}>
    <Datagrid>
      <TextField source="id" />
      <TextField source="name" />
      <TextField source="description" />
      <DateField source="date" />
      <ImageField source="flyer" />
      <EditButton basePath="/events" />
    </Datagrid>
  </List>
);

Текущая ошибка, которую я получаю, - Cannot read property 'data' of undefined, но я могу убедиться в своих журналах, что данные принимаются правильно.


person dnwilson    schedule 27.09.2017    source источник
comment
Невозможно прочитать данные свойства undefined в AOR обычно происходит, когда компонент где-то подключается к состоянию. Вы где-то неправильно написали название ресурса?   -  person kunal pareek    schedule 28.09.2017
comment
возможно, но я так не думаю   -  person dnwilson    schedule 28.09.2017
comment
Другое место, где ваш код ищет ключ данных, находится в оставшемся клиенте выше. Я бы предложил просмотреть код и посмотреть, не определены ли где-нибудь параметры.   -  person kunal pareek    schedule 29.09.2017


Ответы (1)


Попробуйте использовать data в качестве ключа корневого уровня в ответе json. Измените events на data, например:

{
  "data": [
    {
        "id": 13,
        "name": "Event 1",
        "description": "test"
    },
    {
        "id": 16,
        "name": "Event 2",
        "description": "dsadfa adf asd"
    }
  ],
  "meta": {...}
}
person fairchild    schedule 11.03.2018