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.
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))
}
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
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)
}
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.
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
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)
})
}
Between ruby and js its about half as many lines of code as before!
Top comments (0)