Hammer, N(R)ails, and some Java(Script)
Author: John on September 25, 2015
Although at times I feel like taking a hammer and some nails to bang some sense into my code, what I actually will be discussing today is related to a feature I was working on that required some updates to our Ruby/Rails code and JavaScript. I typically find myself using pry to help me work through issues with the ruby code. But for this feature, I needed to grab my hammer, make that Chromes' Developer tools, to assist in my debugging.
A little background first - assume we have a view that has a form on it. A new requirement has been requested for us to add an upload file feature to that same view. No problem, I can use form_tag to accomplish this task. After making some changes, I was able to confirm that the view in question displayed the original form with a submit button, and a form to handle choosing a file to upload and its' corresponding upload button. Below is an example of the first form_tag, and the second new form_tag:
ORIGINAL
= form_tag({action: 'update'}, id: "original-form") do
= button_tag 'Submit', id: 'confirm-button', type: 'button', disabled: @nurny.disable_submit_button?
ADDITIONAL
= form_tag({action: :upload}, multipart: :true, id: "upload-file") do
= file_field_tag 'upload_file'
= button_tag 'Upload', id: "upload-button", class: "good", type: 'button', disabled: false
Something to keep in mind, when you have multiple forms on the same page, is to be sure you have a way to uniquely identify each form. With the code updated, I went to test the forms. To my surprise, when clicking either the Submit button or the Update button, nothing seemed to happen. For the submit button, I could see Rails going through the motions of hitting the controller and associated update action, but the page didn't refresh with the data as I was expecting.
Well, this would be interesting. I couldn't pry my way into seeing what was happening. So I viewed my problem page in Chrome and pulled up the Developer Tools. After a little digging, and cursing, I saw that my new form, 'upload-file', was nested under the original form. This was causing my issue with neither form being able to properly set their data. What makes this new request a bit of a challenge is that we are building a view by using partials. So I didn't initially catch that I was nesting my new form inside the original one.
How did I notice the new form was nested? Using the Developer Tools, View Source, I observed something like the following:
NOTE: You may notice that I take the liberty to substitute actual syntax with filler syntax - just look for the all capitalized words. I also like to use nurny and bobots as a substitute when needed.
With the nested forms issue resolved, my original form was now working. But my second form still had an issue. I could click on the Choose File button, select and file, and then click on the Upload button. However, nothing happened. At this point I need to grab my cup of JavaScript.
For my initial attack, let's write just enough javascript to get things working - no validation:
#app/assets/javascript/nurny/validation.js
function uploadFile() {
$('#upload-button').click(function() {
var $form = $('#upload-file');
$form.submit();
return true;
});
}
#app/assets/javascript/nurny/bobots.js
$(document).ready(function() {
nurnyBobotter();
setUnsubmit();
uploadFile();
)};
With the above code in place, I was successful in choosing a file to upload, and by clicking the upload button, getting my data processed as planned. In my ruby code I am validating that the user actually choose a file, else I present an error. However, we would like to catch the 'no file chosen' issue before being processed by our controller. Yup, you guessed it - we need some more javascript.
I updated my previously created function, uploadFile() with the following:
#app/assets/javascript/nurny/validation.js
function uploadFile() {
$('#upload-button').click(function() {
var $form = $('#upload-file');
var $uploadedFiles = $('#upload_file');
if ($uploadedFiles.length <= 0) {
displayFlashError("You have not chosen a file.");
return false;
}
$form.submit();
return true;
});
}
To my surprise, nothing happened. In fact, now my Upload File form wouldn't work at all. Argh! Back to Chrome and the Developer Tools. Using the console feature, I tried out a few things to see what going on:
[no file chosen]
var $uploadedFiles = $('#upload_file');
undefined
$uploadedFiles
<input id=""upload_file"" name="" tabindex=""3017"" type=""file"" />
$uploadedFiles.length
1
[a file was chosen]
var $uploadedFiles = $('#upload_file');
undefined
<input id=""upload_file"" name="" tabindex=""3017"" type=""file"" />
$uploadedFiles.length
1
Hmmm, whether a file has been selected or not, I am getting a length of 1. Obviously I'm doing something wrong. Off to the net to search for possible solutions. I like to give credit to the following Stack Overflow: http://stackoverflow.com/questions/833012/how-to-validate-a-file-upload-field-using-javascript-jquery
Using what I learned from the above link, and first testing it in Chromes' Developer Tools, I updated my code as illustrated below:
[console - Development Tools]
var $uploadedFiles = $('#upload_file').val();
undefined
$uploadedFiles
"C:\fakepath\sample_file_good-info.csv"
$uploadedFiles.length
44
app/assets/javascript/nurny/validation.js
function uploadFile() {
$('#upload-button').click(function() {
var $form = $('#upload-file');
var $uploadedFiles = $('#upload_file').val();
if ($uploadedFiles.length <= 0) {
displayFlashError("You have not chosen a file.");
return false;
}
$form.submit();
return true;
});
}
This wraps up today's post, but hopefully you will find it useful. I have spent a lot time recently, debugging using pry, that I had to dust off another very valuable tool in my tool box. No, not my hammer, but the handy Developer Tools in Chrome.
Learn Something New Every Day
Last Edited by: John on November 10, 2015