RoR: Development of a Function to Autosave Data Entered by a User in a Web Application Form
Gone were the days when a user would lose entries in web forms after a shutdown or an interruption. Have you ever had to retype content in a web form after a shutdown, network failure, or closing pages? If yes, you can attest to how frustrating that can be. With an Autosave Function, this problem is now a thing of the past. Thanks to recent advancements in web technologies. In this article, we will look at how we implement the autosave feature using the Ruby on Rails framework.
Never Lose User Data Again: Implement Autosave in Your Rails App
Providing Ruby development and consulting services to build custom software.
Our Expertise with Autosave Function Using Ruby on Rails
In the process of working on one of our projects, it became necessary to implement the autosave data function. This would make it more convenient to fill in the data and at the same time not lose it when closing the pages. We used the Ruby on Rails framework as the main server.
When considering the server to which requests will be sent, we decided to use Sinatra, a minimalistic web framework written in Ruby. Sinatra was considered the suitable web framework of choice because of the following:
- Simplicity;
- Speed of operation.
A key-value data store in Redis memory was chosen as a temporary data storage in order to reduce the load on the database. A ruby library, a tool for performing a background job, was chosen for creating Resque background tasks.
Check Out Our RoR Signature Case Study
Built from scratch LMS for K-12 to manage academic operations targeted for the US market with PHP, RoR and React JS technologies used.
How It Was Implemented
There were various learning materials in our project. Our partners provided some of the resources to us as plug-in libraries, while our team created some materials, as well. The concept and implementation of these training materials were different. And we had more than 30 of them in the project at that time.
To add a js callback, when triggered, a request with the changed data will be sent to a fast server. The callback was supposed to fire as soon as the user changes or enters new data in any part of the test task. All callbacks were added with different response delay logic. This was calculated and selected individually for each training material. It was done in order to minimize the heavy load on the Sinatra server and not miss the entered data in case of any problems on the user’s side.
Each test task that is assigned to a student (hereinafter referred to as the user) can contain a large number of various educational materials. After the user performs an action (typing text, drawing, dragging a block, dropdown, checkbox, etc.), while responding to any educational material, a callback is triggered according to a certain logic that collects data in one package (globalId — id) and sends them to the Sinatra server.
GlobalId enabled us to understand which test task the student is working on; because each test task is associated with a user, this is enough to identify it. State Data is the data that has been changed in a particular test task. For the first time for this test task, we sent the entire structure with the user’s responses. If some responses had already been saved, then we sent only the data that was changed by the user before the callback was fired. Thereby understanding the relevance of the data
Sinatra accepts the request and checks if there is such a key (globalId) in the Redis storage. If it does not exist, it creates an entry in the Redis storage of the form “globalId: stateData.” After that, using the convenient Pub / Sub tool available to us in Redis, we do a PUBLISH of the key we saved in Redis to a specific channel with an arbitrary name, like ’autosave’. If the incoming key already exists in the Redis store, we compare their timestamp and update the entry stored in the Redis store with more recent data.
The use of a Sinatra staging server and a Redis data storage is for one purpose only: to reduce the high load on the main database.
While the background job is in the queue and has not yet been executed, the data is taken from the Redis storage, if it exists there. If it is not there, then we classically query them from the main database. This applies to all user requests for this training material (page reload, browser closing/opening).
Why We Use Redis Pub/ Sub Tool
Now let me explain a little why we use the Redis Pub/Sub tool. It is necessary so that we can find out which block of data should be saved to the main database. The PUB/SUB concept works as follows:
On one hand, we can publish any arbitrary data that we want to transfer to a channel with a specific name. On the other side, we have a process running that subscribes to this channel and receives all the messages that were sent there. Therefore, on the side of the main server, we launched a daemon; constantly listening to the channel in the form of a Rake task, which is subscribed (SUBSCRIBE) to the same channel to which we published the globalId.
As soon as the key (globalId) is published to the Redis channel and the daemon receives this key, it simply queues a special background job in the Resque queue. All the main logic will already be performed in the Resque queue. When the background job is executed, we first take the data stored in Redis by the incoming key (globalId).
And as soon as the reading has taken place, we immediately delete the data associated with this key from Redis. After that, we make a get request to the main database and get the timestamp of our training material. If the data received from Redis is more recent than what is stored in the main database, we update the State Data of the test task in the main database.
A function was also provided to notify the user if, for some reason, the Sinatra server does not respond and the data cannot be automatically saved. The notification is a pop-up window in which we warn the user that autosave is not working at the moment and suggest that they do not forget to click the Save button after the test task is completed. As soon as the server starts up, this message disappears and all data is automatically saved.
Wrapping Up
In conclusion, implementing an autosave function significantly enhances the user experience of your web application. By preventing data loss and improving user confidence, autosaving can lead to increased user satisfaction and engagement. If you’re developing a Ruby on Rails application, consider incorporating this valuable feature to streamline your user’s experience.
This implementation allowed us, with a small investment both in time and money, to implement a reliable data autosave function that is easy to use and invisible to the user. At Aristek Systems, we are dedicated to implementing cutting-edge and immutable web functions. Our experience and expertise with Ruby on Rails development and consulting are unmatched.