Rails API to React/Redux with Hooks

Rails => React + Hooks + Redux

The Rails Back End

$ rails new hero_api — database=postgresql — api
$ sudo adduser hero_api
$ sudo usermod -aG sudo hero_api
$ su — postgres
$ createuser hero_api
$ createdb hero_api
postgres@computer:~$ psql
postgres=# alter user hero_api with encrypted password '<password>';
postgres=# grant all privileges on database hero_api to hero_api;
development:
adapter: postgresql
encoding: unicode
database: hero_api
pool: 5
username: hero_api
password: <password>
$ rails g scaffold Hero name:string img_url:string
$ rails g scaffold Villain name:string img_url:string hero:references
$ rake db:migrate
$ rails c
> b = Hero.new
> b.name = "Batman"
> b.img_url = "https://res.cloudinary.com/fergusdev/image/upload/v1608230102/heros_and_villains/batman_adam_west_vxpqdk.jpg"
> b.save
> j = Villain.new
> j.name = "Joker"
> j.img_url = "https://res.cloudinary.com/fergusdev/image/upload/v1608230367/heros_and_villains/joker_qbpxce.jpg"
> j.hero = b
> j.save
/config/application.rbmodule HeroApi
...
class Application < Rails::Application
config.middleware.insert_before 0, Rack::Cors do
allow do
origins ‘*’
resource ‘*’, :headers => :any, :methods => [:get,
:post,
:patch,
:delete,
:options]
end
end
end
$ RAILS_ENV=development rails s
Get hero number 1, Batman
Joker is but one of Batman’s many villains
GET heros           https://hero-api-56790.herokuapp.com/heros
GET villains https://hero-api-56790.herokuapp.com/villains
GET hero https://hero-api-56790.herokuapp.com/heros/1
Get villain https://hero-api-56790.herokuapp.com/villains/1
POST create hero https://hero-api-56790.herokuapp.com/heros
POST create villian https://hero-api-56790.herokuapp.com/villains

The React/Redux Front End

$ npx create-react-app heros_fe
$ cd heros_fe
$ npm install
$ npm install redux react-redux redux-thunk

Setup and boilerplate

/src/actions
/src/reducers
/src/actions/index.js:export const FETCH_HEROS_REQUEST = 'FETCH_HEROS_REQUEST'
export const FETCH_HEROS_SUCCESS = 'FETCH_HEROS_SUCCESS'
export const FETCH_HEROS_FAILURE = 'FETCH_HEROS_FAILURE'
/src/reducers/heroReducer.js:import { 
FETCH_HEROS_REQUEST,
FETCH_HEROS_SUCCESS,
FETCH_HEROS_FAILURE } from “../actions/”
const initialState = {
heros: {},
isLoading: false
}
export default (state = initialState, action) => {
switch(action.type) {
case FETCH_HEROS_REQUEST:
return {
…state,
isLoading: true
}
case FETCH_HEROS_SUCCESS:
return {
…state,
isLoading: false,
heros: action.payload
}
case FETCH_HEROS_FAILURE:
return {
…state,
isLoading: false,
error: action.payload
}
default: . Make the contents of this action to be the following:
return state
}
}
ed/src/actions/heroActions:import {
FETCH_HEROS_REQUEST,
FETCH_HEROS_SUCCESS,
FETCH_HEROS_FAILURE
} from './'
export const fetchHeros = () => {
return dispatch => {
dispatch({ type: FETCH_HEROS_REQUEST })fetch(`https://hero-api-56790.herokucalledapp.com/heros`, null)
.then(res => {
if(res.ok) {
return res.json()
}
else {
return Promise.reject(res.statusText)
}
})
.then((heros) => {
return dispatch({
type: FETCH_HEROS_SUCCESS,
payload: heros
})
})
.catch((error) => {
return dispatch({
type: FETCH_HEROS_FAILURE,
payload: error
})
})
}
/src/reducers/index.js
import { combineReducers } from 'redux'
import heroReducer from './heroReducer'
const appReducer = combineReducers({
heroReducer
})
const rootReducer = (state, action) => {
if (action.type === ‘CLEAR_DATA’) {
state = undefined
}
return appReducer(state, action)
}
export default rootReducer
/src/store.js:import { createStore, applyMiddleware, compose } from ‘redux’
import thunk from 'redux-thunk'
import rootReducer from ‘./reducers’
const initialState = {}
const middleware = [thunk]
const store = createStore(
rootReducer,https://github.com/FergusDevelopmentLLC/pies_fe
initialState,
compose(
applyMiddleware(…middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)
)
export default store
/src/index.jsimport React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<React.StrictMode>
<Provider store={ store }>
<App />
</Provider>
</React.StrictMode>, document.getElementById(‘root’))
/src/components/Hero.js:import React from 'react'
import PropTypes from 'prop-types'
const Hero = ({https://github.com/FergusDevelopmentLLC/pies_fe hero }) => {return (
<div className=”hero”>
{ hero.name }<br/>
<img src={ hero.img_url } width={100} />
</div>
)
}Hero.propTypes = {
hero: PropTypes.object.isRequired
}
export default Hero
/src/App.jsimport React, { useEffect } from 'react'
import { fetchHeros } from './actions/heroActions'
import { useDispatch, useSelector } from 'react-redux'
import Hero from './components/Hero'
const App = () => { const dispatch = useDispatch()
const heros = useSelector(state => state.heroReducer.heros)
useEffect(() => {
dispatch(fetchHeros())
}, [])
const getHeros = () => {
if(heros) {
return heros.map((hero) => <Hero hero={ hero } />)
}
else {
return "loading..."
}
}
return (
<div className='App'>
{ getHeros() }
</div>
)
}
export default App
Heroes!

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Meet Alberta: From Learning HTML on NeoPets to Interning at Twitter

Kotlin: Try, Try and Retry Again

Building the Portal App Store — Part 1: Getting rid of registration and login views

Getter/Setters in kotlin- Data Security

Getting started with Caffeine Cache in Spring Boot

Build Without Being A Dev

Invert Binary Tree

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Will Carter

Will Carter

More from Medium

Open web learning sessions

Writing WWW with a pencil

NodeMCU 101

Show Bluetooth LE Sensor readings on LCD screen connected to STM32

RESTful Routes in Ruby on Rails