Wednesday, March 19, 2014

Migrations and more Ajax

I had a pair programming session with Fernando last night where we set up the functionality for storing whether a user challenge has been completed and then marking it as completed on the challenges page (by displaying a Bootstrap glyphicon checkmark next to the completed challenge). However, we still need to decide whether a user should be allowed to retake a challenge or whether it is a "one-time only" thing. I think it might be good to allow users to retake challenges since they may need to do it again to maintain a habit. We also brainstormed about how certain parts of the code should be handled (such as what should happen if the user misses a check-in), which will have to be brought up at our next team meeting so we can make these decisions as a group.

Prior to the coding session with Fernando, I had initially played around with using "rails g migration" to add the boolean "finished" column to the user challenges. This worked well (with code added to the migration file to make sure the default value for finished was "false"). There seems to be a basic convention for performing migrations of different types, which look like the following:

 rails g migration change_data_type_for_progress_in_user_challenge #This is what we used for the boolean.
 rails g migration add_<column_name_here>_to_<table_name>
 rails g migration change_data_type_for_<column_name>_in_<table_name>
 rails g migration remove_<column_name>_from_<table_name>

However, as I was testing this, I noticed an issue with the progress bar itself. For challenges where the duration (times per week * number of weeks) did not evenly divide into 100, the percentage amount for each check-in is (obviously) a decimal value . Since the progress was being stored in the database as an integer, decimal values were being rounded up before being sent to the controller via Ajax. While this will work for small durations or durations that divide evenly into 100, this approach is very, very bad if you want any kind of precision for the progress value. I had initially noticed the problem when I added some text under the progress bar that would tell the user how many check-ins they had completed out of the total number that they had to do. Because of the rounding errors, the check-ins were not adding up (e.g. it would take 15 check-ins to get to 100% instead of 16). Also the rounding errors themselves would compound as the number of check-ins increased.

Therefore, when I met with Fernando last night, we discussed this issue and decided that the best solution was to convert the progress columns in the database (in the histories and user_challenges tables) to decimal values, which can be done with migrations, in particular, the "change" migration, as shown in the migration examples above. We chose to use the "decimal" type instead of "float" because it is more precise and precision is what we need for the progress bar.

Then, after applying the changes to the database, we had to update the Javascript for the progress bar so that it would use and store the decimal value instead of rounding it off. But, when we went to test out the updated code, the decimal value produced by the progress calculations in the Javascript were not being properly saved to the database. Instead they were being truncated prior to saving (i.e. 6.75 would be saved as 6). We used the "raise" keyword in the users controller and "console.log" in the Javascript to try to debug the problem. The Javascript was storing and calculating the value correctly, but when we printed out the Ajax URL and parameters that were being sent to the users controller, we discovered that the progress parameter was being truncated. The URL would contain the correct progress value, but the params[...] array contained only the truncated value of the progress. Since the params[...] array is used to get the progress value and store it in the database, this was where the problem was occurring.

At first we thought that maybe the "." in the decimal value was some sort of reserved character in Ajax. However, this did not make sense because the URL contained a "." and it was parsed just fine (and why would URLs disallow "." since these are used all the time for sending image requests (image.jpg, etc.)). Then we thought that maybe there was some restriction on sending decimal values via Ajax. Again, this did not make sense because I had seen examples where values such as latitude and longitude were passed via Ajax and were not truncated. After nearly an hour of searching through forums, I found a post on stackoverflow.com where another person had had a similar issue. It turns out that this was due to problems with the parameter parsing done server side (not with Ajax). I could not find a way to change this for the Rails server, so I did some more googling and found out that sending the progress via JSON (instead of as a "script") would allow us to prevent Rails from truncating the parameters:

        $.ajax({
          dataType: 'JSON',
          async: false,
          url: "/create_history/" + currProgress,
          data: {"newProgress":currProgress}

        });

Then in the users controller, we can grab the decimal progress value by using params[:newProgress].

Once this problem was solved, we made an update to the Haml and Javascript that displayed the progress bar, adding a hidden congratulations modal that could be displayed using jQuery when the user completed a challenge. We also added a button to the modal that the user can click to take them to the challenges page to find another challenge.

No comments:

Post a Comment