DEV Community

Cover image for Sinatra-React Project Server-Side Cool Features
bperez3237
bperez3237

Posted on • Edited on

Sinatra-React Project Server-Side Cool Features

I ran into an interesting issue while working on my Sinatra-react project that opened my eyes to some of the benefits of server side coding.

Just for some context into my project, my idea was to create a project schedule planner and cost tracker. The user would be able to view the schedule of activities on one page and view all the cost transactions on another page. Each cost belongs to one activity, and each activity has many costs. I wanted the activities to have full CRUD capabilities so someone could change the schedule as things change in the project. The activities have “order” as a parameter so the schedule can sort the activity elements in the correct order.

Image description

In creating the “DELETE” request, I realized multiple changes needed to be made to my program for everything to keep making sense. In addition to updating the activities state variable, I would need to update the costs and order of activities. Deleting any activity would change the order of the activities after it. And if I deleted an activity, it would affect any costs with that activity_id.

Initially I thought to do this with multiple fetch requests. I would complete the "DELETE" request, then do a "GET" for cost and a "GET" for activities.

function handleDelete(id) {
        fetch(`http://localhost:9292/activities/${id}`,{
            method: "DELETE",
        })
        const updatedActivities=activities.filter((activity)=> activity.id !==id)
        setActivities(updatedActivities)
        setToggleInfo(!toggleInfo)

        fetch('http://localhost:9292/costs')
            .then((r)=>r.json())
            .then((data)=>setCosts(data))

        fetch('http://localhost:9292/activities')
            .then((r)=>r.json())
            .then((data)=>setActivities(data))
    }
Enter fullscreen mode Exit fullscreen mode

This actually isn't too bad considering it seems ridiculous to do in multiple fetch requests. It wasn't until the next day the idea occurred to me to modify the return data from the "DELETE" request, and update the activities and costs on the backend. If I returned a hash from the delete request I could cleanly update both cost and activities states. My code simplified to:

in ruby:

delete '/activities/:id' do
    activity = Activity.find(params[:id])
    activity.costs.each {|cost| cost.destroy}

    start = activity.order - 1
    Activity.all.sort_order[start..].each do |act|
      act.update(order: act.order-1)
    end
    activity.destroy

    res = {'activities': Activity.all, 'costs': Cost.all}
    res.to_json
end
Enter fullscreen mode Exit fullscreen mode

and in js:

function handleDelete(id) {
        fetch(`http://localhost:9292/activities/${id}`,{
            method: "DELETE",
            headers: {
                'Content-Type': 'application/json'
            }
        })
            .then((r)=>r.json())
            .then((obj)=> {
                setActivities(obj.activities)
                setCosts(obj.costs)
            })
        setToggleInfo(!toggleInfo)
    }
Enter fullscreen mode Exit fullscreen mode

Maybe not a drastic change in number of lines of code, but the logic makes so much more sense now. It then gave me another idea.

I had completed the "PATCH" request feature a couple days before... and it was a complete mess.

Image description

On the server-side, I had essentially nothing. My "PATCH" request would update the order and return the newly update activity object. I would then have to do another "PATCH" to update the order on the activity it was swapping with. All while keeping the state properly updated.

So, instead of that mess of code, I was going to update the order of both activities from the server side, and then send all the activities so all orders would be kept up to date. Using ActiveRecord, I could make these same changes with less code, and less work updating state on the frontend. I was able to simplify my code to this:

in ruby:

patch "/activities/:id" do
    activity = Activity.find(params[:id])
    swap_activity = Activity.find_by(order: params[:order])
    difference = params[:order] - activity.order

    unless params[:order] < 1 || params[:order] > Activity.all.length
      activity.update(order: params[:order])
      swap_activity.update(order: swap_activity.order - difference)
    end
    activities = Activity.all
    activities.to_json
  end
Enter fullscreen mode Exit fullscreen mode

and in js:

 function handleOrderChange(e, order, id) {
        e.preventDefault()
        const newOrder = parseInt(order)+parseInt(e.target.value)
        fetch(`http://localhost:9292/activities/${id}`, {
            method: "PATCH",
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({order:newOrder}),
        })
            .then((r)=>r.json())
            .then((activities)=> {
                setCurrentActivity(activities.find((activity)=> activity.id===id))
                setActivities(activities)
            })
    }
Enter fullscreen mode Exit fullscreen mode

Between ruby and js its about half as many lines of code as before!

Top comments (0)