For part 3, I will be adding more functionality to full stack app described in parts 1 and 2 linked below. If you’re following along, be sure to check these out first.

part 1: https://benton-westergaard.medium.com/build-a-simple-fullstack-app-using-rails-and-react-460ebec3a1bc

part 2: https://benton-westergaard.medium.com/simple-full-stack-app-with-rails-react-ii-bd850f53ad3e

For part three of this series, I want to add the ability to delete locations. Deleting (destroy) is the easier than editing(update), so I’ll do this first, and then add the edit feature to the next blog.

Starting first with the backend, I need to add a destroy method to the locations_controller.rb file. Below the ‘create’ method, I add the following:

def destroy
@location = Location.find(params[:id])
@location.destroy
render status: :no_content
end

The delete method is straightforward: find the location by it’s ID and remove (destroy) it. Now, when my front end sends a delete request, Rails will know what to do with it. That’s it for the front end!

Notice that I’ve added a ‘no content’/204 error. This isn’t absolutely required, but might help later when functionality becomes more complex.

First step to integrating this into the front end is to create a button. So, to the LocationItem.js file, I add a simple button below the other items.

<button className="delete-button">DELETE LOCATION</button>

The button now shows on the screen, although it won’t do anything. I added a class name so I can adjust the styling, and make it as intuitive as possible to users the button function. To accomplish that, within App.css, I add the following code, which gives a big red button labeled “DELETE LOCATION.”

.delete-button {
background-color: red;
color: white;
}

Now, to make the button accomplish something. First, I want to tell react that when users click the button for a location item, it will know to remove this item from the item collection. I want to sort this out before connecting to the backend/render pessimistically. Since this will involve changing location state, I will begin with the App.js level and create a new function. This will filter locations to all those NOT associated with the location id for the button clicked, then change state to this new list (filteredLocations):

deleteLocation = (id) => {
let filteredLocations = this.state.locations.filter(location => location.id !== id)
this.setState({
locations: filteredLocations
})
}

Also within App, I need to pass down deleteLocation to the LocationContainer in the render, although not invoking it, but rather, passing it as a prop to to the next component, LocationContainer.js.

<LocationContainer deleteLocation={this.deleteLocation} locations={this.state.locations} />

Within LocationContainer.js, I add this (desctructured) prop:

export default function LocationContainer({locations, deleteLocation }) {

Now, I just need to add the function to the showLocations map:

return locations.map(location => <LocationItem key={location.id} {...location} deleteLocation={deleteLocation}/>)

Since this is a functional component, I don’t have to use ‘this’, just the (again, destructured variable {deleteLocation}.

At this point, it’s a good idea to make sure each item has the deleteLocation function by using the browser tool>components. Below is a screen grab with the delete function highlighted for LocationItem(key=”5"):

The next step is to make the button click event send a location id back up to App so it can be deleted. For this, I go down one more level to the locationItem.js component, and add a handleClick method to the button. I also need to add the destructured prop and id to the default function, so the component will know WHICH location to delete:

import React from 'react';export default function LocationItem({
id, name, baseball, basketball, football, hockey, total_teams, capital, deleteLocation}){
const handleClick = (event) => deleteLocation(id)

return (
<li className="location-item">
<h2>Location: {name}</h2>
<h4>MLB team(s): {baseball}</h4>
<h4>NBA team(s): {basketball}</h4>
<h4>NFL team(s): {football}</h4>
<h4>NHL team(s): {hockey}</h4>
<h4>Total professional teams: {total_teams}</h4>
<h4>Any teams use state capital in their title? {capital}</h4>
<button onClick={handleClick} className="delete-button">DELETE LOCATION</button>
</li>
)
}

Of course, this is only rendered optimistically. If I delete any locations and then refresh the page, they’re back because the database/backend isn’t yet connected. So, back in the App.js component, I need to add a fetch to the deleteLocation function:

deleteLocation = (id) => {
let filteredLocations = this.state.locations.filter(location => location.id !== id)
this.setState({
locations: filteredLocations,
})
fetch(locationsURL + "/" + id, {method: "DELETE"})
}

At this point, any item can be deleted from the front and back end!

--

--