Создание приложения React с серверной частью Rails — часть 1

Поскольку я закончил всю свою курсовую работу в The Flatiron School, единственное, что осталось сделать до выпуска, — это создать приложение React с серверной частью API Rails. Просматривая разделы React и Redux Онлайн-программы веб-разработки, материал показался довольно простым. Мне не терпелось придумать идею проекта и реализовать эти новые библиотеки, которые я только что изучил. Мне пришла в голову идея создать приложение, похожее на Instagram, которое позволяет пользователям публиковать фотографии своих щенков и писать описание или подпись того, что их щенки делают на картинке. В этой записи блога я расскажу, как я создал API Rails, а затем реализовал React для внешнего интерфейса, а затем в следующей записи блога я расскажу, как я создал дизайн сайта.

Первым шагом было создание бэкенда. Я спорил, использовать ли команду Rails new или команду Rails new api для создания исходных файлов. Я решил использовать команду API Rails. Для этого я использовал следующую команду

rails new my_api_name --api

После того, как все файлы были созданы, я следовал следующей документации, чтобы настроить маршруты для API: http://guides.rubyonrails.org/api_app.html. Я использовал функцию маршрутизации пространства имен в config/routes.rb, чтобы поместить api/ перед всеми именами маршрутов.

//config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    resources :images
  end
end

Следующим шагом было создание моих моделей, а затем моих контроллеров. Убедившись, что мой бэкэнд API был построен так, как я хотел, я добавил некоторые начальные данные. Моя модель была очень проста в создании. Я использовал генератор моделей Rails. Поскольку на данный момент у меня есть только модель изображения, мне не нужно беспокоиться о каких-либо ассоциациях. Команда, которую я использовал, была:

rails g model Image

Мой контроллер выглядит следующим образом:

class Api::ImagesController < ApplicationController
def index
    @images = Image.all
    render json: @images
  end
def create
    @image = Image.new(image_params)
    if @image.save
      render json: @image
    else
      render json: {errors: @image.errors}, status: 400
    end
  end
def update
    @image = Image.find(params[:id])
    @image.update_attributes(image_params)
    render json: @image
  end
private
def image_params
    params.require(:image).permit(:imageURL, :name, :description)
  end
end

Затем я следовал инструкциям в этой статье, чтобы подключить бэкэнд Rails к интерфейсу React. Эта статья дает хорошее введение в то, как использовать команду create-react-app. Мой совет по использованию этой статьи для соединения Rails и React — не торопитесь и внимательно читайте. Есть две ключевые вещи, которые вам нужно сделать после того, как вы выполнили инструкции в статье. Вам нужно установить драгоценный камень стойки cors.

gem install 'rack-cors'

Затем вам также нужно будет изменить файл config/initializers/cors.rb, чтобы он выглядел следующим образом:

Rails.application.config.middleware.insert_before 0, Rack::Cors do
   allow do
     origins 'localhost:3000'
resource '*',
       headers: :any,
       methods: [:get, :post, :put, :patch, :delete, :options, :head]
   end
 end

Прежде чем я выполнил два вышеуказанных шага, у меня было много проблем с загрузкой моего приложения на сервер. Эти шаги устранили все ошибки Cors, которые я получал.

Теперь самое интересное — создание внешнего интерфейса приложения с помощью React. Когда мы ссылались на статью о подключении нашего API Rails к нашему приложению React, мы уже создали наше приложение React с помощью команды create react app.

Чтобы приступить к созданию внешнего интерфейса rails, я подключил свое приложение к хранилищу с помощью промежуточного программного обеспечения Provider из библиотеки redux. Я также импортировал create store, applyMiddleware и compose промежуточное ПО из библиотек Redux. Затем я создаю свой магазин с помощью функции createStore().

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware, compose} from 'redux';
const store = createStore(rootReducer, compose(applyMiddleware(thunk), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()))
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

После настройки файла index.js я начал создавать компонент App.js. Этот компонент использует промежуточное ПО BrowserRouter и позволяет нам создать одностраничное приложение (SPA), используя маршруты для подключения всего.

import React, { Component } from 'react';
import Home from './Home'
import Navbar from './Navbar'
import {BrowserRouter as Router, Route} from 'react-router-dom';
import ImagesPage from '../containers/ImagesPage';
import '../App.css';
const App = () =>
    <Router>
      <div>
      <header className="App-header">
        <Navbar />
      </header>
        <Route exact path="/" component={Home} />
        <Route path="/images" component={ImagesPage} />
      </div>
    </Router>
export default App;

Оттуда я добавил контейнеры и компоненты, чтобы создать больше функциональности в самом приложении. Чтобы увидеть, как выглядели другие файлы, обратитесь к репозиторию github.

Одной из самых больших проблем, с которыми я столкнулся при работе с React, были редукторы и действия. В моем файле действий я использовал функцию JavaScript fetch() для извлечения данных из моего API Rails. В моем файле действий было определено 3 функции: getImages(), fetchImage() и addImage().

export function addImage (image) {
  return (dispatch) => {
    return fetch('http://localhost:3000/api/images', {method: 'post', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({image: image})})
      .then(response => response.json())
      .then(image => dispatch({type: 'ADD_IMAGE', image}))
  }
}
export function fetchImage (imageId) {
  return (dispatch) => {
    return fetch(`http://localhost:3000/api/images/${imageId}`)
      .then(response => response.json())
      .then(imageId => dispatch({type: 'FETCH_IMAGE', imageId}))
  }
}
export function getImages () {
  return (dispatch) => {
    return fetch('http://localhost:3000/api/images', {
      headers : {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      }
    })
      .then(response => response.json())
      .then(images => dispatch({type: 'GET_IMAGES', images}))
  }
}

И мой файл редукторов:

export default (state = [], action) => {
  switch (action.type) {
    case 'ADD_IMAGE':
      return state.concat(action.image)
    case 'GET_IMAGES':
      return action.images
    case 'FETCH_IMAGE':
      return action.image
    default:
      return state;
  }
};

После нескольких дней напряженной работы я успешно создал свой проект React с API серверной части Rails. В следующем разделе я расскажу, как я разработал свой проект.

Если у вас есть какие-либо вопросы о моем коде, пожалуйста, оставьте комментарий ниже.