DEV Community

Elias Ventura
Elias Ventura

Posted on

Complex Nested State!

During this third project for FlatIron School we had to learn a lot about Sinatra and ActiveRecord to create databases. With ActiveRecord one of many things we are able to do is create associations between different tables. Then with that information we are able to, through ORM structure, to create objects in the front end that share that same association of the databases in the backend.

class Dog < ActiveRecord::Base
    has_many :walks 
end
Enter fullscreen mode Exit fullscreen mode
class Walk < ActiveRecord::Base
    belongs_to :dog
end
Enter fullscreen mode Exit fullscreen mode

These associations allow us to make ActiveRecordQueries in the back end to the walks table by way of the Dogs table.

Dog.all.first.walks
Enter fullscreen mode Exit fullscreen mode

But it also allows us to make similar method calls in the frontend because it is aware of the association between models, so i can even call dog.walks in the javascript in the front end and it will get information from the database that relates to those walks and create walk objects based on that which is really cool.

I had to learn a lot about setState and updating state for nested object information and how that is useful. It's really important to keep the association that is created in the backend by the models and to represent that in the way the information is manipulated in the front end. This allows us to only make one fetch request to one of the databases but to be able to access all the information from the other database.

fetch("http://localhost:9292/dogs")
    .then((r) => r.json())
    .then((data) => {
      setDogs(data)
    });
Enter fullscreen mode Exit fullscreen mode

But one interesting thing is that when fetch request are made specifically for the Walks table, whether it be for posting walks or deleting walks or updating walks, since there is no state for the walks table and there is only state for the dogs table we have to setState for the dogs table to be able to rerender the parent component and instantly get the updated state for the associated walk.

function addWalk(walk) {
        const newWalks = [...dog.walks, walk]
        dog.walks = newWalks

        const filteredDogs = dogs.filter( d => {return d.id !== walk.dog_id})
        const newDogs = [...filteredDogs, dog]

        setDogs(newDogs.sort((a, b) => { return a.id - b.id }))
        setClicked(!clicked)
          }
Enter fullscreen mode Exit fullscreen mode

Here i had to call the setDogs to set state of the dogs after adding a new walk, and this is called directly in the POST request made to the walks table. This is important because even though the route may work and the walk may be created state isn't update and so you would have to refresh the page to see the newly created walk. But since the setState is connected to the actual fetch request the information is update instantly and you wouldn't have to refresh the page to update the component. And that is the really neat thing about having the association between the models and using that association to be able to manipulate both databases.

Now this can be applied to any of the CRUD functions that are common in the front end of the application. Where if we have a DELETE request, well we would have to setState there, and if we had a PATCH request, we would also have to update state there as well. This ensures that the component is rendering the most recent changes in anyway to the information in the databases.This can get confusing be cause it usually involves a multiple step call back function that is passed into the fetch requests.

function deleteWalk(walk) {
        let index = dog.walks.findIndex((w) => { return w.id === walk.id})
        dog.walks.splice(index, 1)
        const newDogs = [...dogs]
        setDogs(newDogs)
    }
Enter fullscreen mode Exit fullscreen mode


The steps for example of deleting a walk would include finding the walk in question by id, using .splice to remove the walk from the array. Then creating a copy of the dogs array which has been slightly altered by removing the walk from one of the dogs dog.walks array. And the passing the created copy of the dogs array into setDogs which will rerender because the array being passed in is slightly altered, and the the parent component will update and display the updated information without having to refresh the page.

It is sometimes confusing to keep track of all the state changes so its important that you are setState whenever you make one of these types of CRUD request to either of the databases.

Top comments (0)