jQuery Remotipart sending [object Object] to server - javascript

I'm trying to upload a file to my Rails application with ajax. To facilitate this, I have included the jQuery.remotipart gem.
// app/assets/javascripts/application.js
//= require jquery.remotipart
I have a form for uploading files. These files are processed by CarrierWave.
<%= form_for #import, remote: true do |f| %>
<fieldset>
<%= f.label :file, "Attach a CSV file" %>
<%= f.file_field :file %>
</fieldset>
<%= f.submit :upload %>
<% end -%>
Unfortunately, when I submit the form with a file attached, it doesn't seem to arrive at my controller action correctly. The params hash has stringified JS objects as keys.
Started POST "/file_imports" for 127.0.0.1 at 2012-11-06 01:00:49 +0000
Processing by FileImportsController#create as JS
Parameters: {"object Object"=>{","=>{"object Object"=>{","=>{"object Object"=>nil}}}}}`
In Chrome's Dev Tools, I can see that this is indeed the form data that is being sent to the server:
The form works perfectly when I remove remote: true (of course, it sends a HTML request rather than a JS request in that case).
Anyone have any idea what I'm doing wrong? By the way I'm using Rails 3.2.8 and Remotipart 1.0.2 (latest).
Edit: Did some more digging.
Looking into the Remotipart source, I can't seem to understand what it is supposed to do. For example, in vendor/assets/javascripts/jquery.remotipart.js, Line 22 has the following:
settings.data = form.serializeArray();
A little further down, the settings are sent to the server via $.rails.ajax(settings).
The $.fn.serializeArray() method returns an array of JS objects. If we assign them to the data attribute of a call to jQuery.ajax(), that would account for the serialized object parameters I'm seeing on the server. We need to pass an object as the data attribute, not an array of objects?
However, when I try to flatten the array into one object, the whole thing breaks and a HTML request is sent to the server instead of a JS one. I think it has something to do with the fact that jQuery.ajax.processData == false.
I have an issue on the Remotipart Github.

After a ton of debugging and reading through lots of code, I finally have the latest gem working with Rails 3.2.8. I was nailed by three gotchas:
(1) I was disabling my file input field prior to form submission and this causes remotipart to ignore it for inclusion in the iframe submission. You must make sure your file inputs are enabled. This is the direct cause of the bug you are seeing.
(2) In the course of my debugging, I was overriding jquery.iframe-transport with the latest upstream source and it doesn't have support for the X-Http-Accepts hidden variable in the iframe. You must use the version bundled with the remotipart gem.
(3) Don't forget to wire up a callback for ajax:complete on the form if you are using a datatype other than script. This is the default if you don't specify dataType in the global ajax options, or use the data-type attribute on the form.

Related

Devise logout not working

I'm using the latest version of devise and rails 4.2.4.
I've my home page
public/index.html
which contains heavy javascript. But when I load it from some other page, it doesn't load with all the effects. So included
$(document).on('page:load', ready);
<script src="/js/modernizr-2.6.2.min.js"></script>
<script src="/js/main.js"></script>
in application.js file.
But then
Logout
<%= link_to "Logout",destroy_user_session_path, method: :delete %>
doesn't work! It gets rendered as GET /users/sign_out.
When I remove those links from application.js, it works fine.
Any workaround for this issue?
Your javascript has an error in it.
--
Each time you use method: :delete or method: :patch, Rails populates a form with the appropriate verb, using Javascript to set it correctly:
[link_to] dynamically creates an HTML form and immediately submit the form for processing using the HTTP verb specified. Useful for having links perform a POST operation in dangerous actions like deleting a record (which search bots can follow while spidering your site). Supported verbs are :post, :delete, :patch, and :put. Note that if the user has JavaScript disabled, the request will fall back to using GET
The above is true if your javascript is broken (IE you have an error preventing it from working properly on the page).
--
Since you haven't posted your JS, I cannot give you any specifics.
However, I can say that your JS should be as unobtrusive as possible.
Using <script> anywhere in your Rails app is bad practice; you should have the files concatenated in your application.js with the help of sprockets manifest directives:
#app/assets/javascripts/application.js
//= require main
//= require modernizr
The issue is that most browsers do not support the DELETE method, the request will actually be submitted as GET, with a data-method="delete" attribute. This relies on the "Unobtrusive scripting adapter for jQuery" (jquery-ujs) being loaded by your page.
If you were using the standard rails templates, the 'application.js' manifest file would take care of that for you, but given that you are putting your index.html in the public directory you will have to manually include both jquery and jquery-ujs in your header.
An alternative is to change the route to logout to actually use GET (you will anyway have issues with the PUT and PATCH methods as well), adding this to your devise config (from devise wiki):
# config/initializers/devise.rb
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :get
If you plan to use rails you should find out why you are having issues with the standard rails way of dealing with view templates. I use a lot of javascript-heavy pages, and they work just fine. Plus you get all the benefits of the asset pipeline.

javascript being sent everytime ajax requests rails app

I have a rails app that gets requested cross domain (I use rack-cors to accomplish this cross domain request without jsonp) through this ajax: It responds with html
//to ensure cache=true gets passed
$.ajaxPrefilter('script', function(options) {
options.cache = true;
});
//ajax requests html
$.ajax({
beforeSend: function (xhr) {
xhr.setRequestHeader ('Authorization', api_key);
},
dataType: 'html',
type: 'GET',
url: url+'/gwsearch/ajax_search?d1='+d1_val+'&d2='+d2_val,
crossDomain: true,
success:function(result){
$("#display").html(result);
},
error: function(result) {
$('#display').html('Unauthorized client.');
}
It responds with HTML that is displayed in #display. It has this script tag included in the html
<script src="http://localhost:3000/assets/application.js" type="text/javascript"></script>
I have input buttons on the newly displayed rails app, they look like this:
<%= form_tag plans_collapse_plans_path, :method => 'post', :remote => true do %>
<%= hidden_field_tag(:plangroup_id, plangroup.id) %>
<%= image_submit_tag "collapse.png" %>
<% end %>
Clicking on the input button does a POST. The problem is that the input button will POST as many times as I've requested the cross domain rails app. If I've requested the app 5 times, when I click an input button on the app, it will POST 5 times.
No matter how many times I send the initial ajax request, I still only have one application.js present; it is not physically cached more than one time.
EDIT:This is what my cache looks like, as you can see, only one application.js:
The collapse_tplans POSTs all correspond to the same application.js file, same line. If i had loaded the initial ajax request 6 times, I would have 6 collapse_tplan POSTs from application.js
My guess is that the script tag in the html page being sent is initializing a new version of jquery (since jquery is contained within application.js) and also, possibly duplicates of other things that are being loaded in application.js each time it is sent through the script tag. With that said, under Network in Chrome, I can only see application.js being requested once, no matter how many times I execute the ajax request.
Any ideas? I need my input button to only POST once, like it should be doing. I'm truly stumped with this one.
As #natedavisolds said, I guess your application.js script is executed 5 times, and the click hanlder of your button or the submit handler of your form is attached 5 times.
The fact that application.js is requested only once does not tell you how many times it is executed.
Try adding the following line at the beginning of the application.js script :
console.log('application.js executed');
and check your browser console to see how many times the message appears.
From your script's name, application.js, I guess it is meant to initalize the whole page, while your ajax request looks like it is only filling the #display node with search results.
You will have to refactor your application.js file :
Read the code in your application.js file, and split the code in two parts : the part that concerns setting up the #display div, and the remainder.
Move the first part in a separate results.js (or whatever name you see fit).
Remove the <script src="application.js"> node from the response to the /gwsearch/ajax_search request, and replace it with a <script src="results.js"> node instead
Since you are using remote:true on the form, my theory is that rails.js is attaching a delegated event on the document element each time the script is loaded. 5 loads = 5 events = 5 ajax calls.
To fix it you could:
Remove the remote true and roll your own making sure it only happens once.
Remove the delegated events on document before loading a new script.
Try: (I am guessing here)
success:function(result){
$(document).undelegate('submit.rails');
$("#display").html(result);
},
Explanation:
Every time rails.js runs, a submit.rails event is added to the stack of events on document. When you insert your html into the page, the rails.js code runs. So, we undelegate the events first, then load the event back in.
The answer to this problem was to stop my application from serving application.js and host it on the client. I did this by the following:
app/views/layout/application.html.erb
I commented out the portion that serves application.js
<!--# <%= javascript_include_tag "application" %> -->
In my client, I added
<script src="https://myapp.herokuapp.com/assets/application.js"></script>
So the client serves application.js, and the rails html response gets sent without application.js. Hope this makes sense to everyone, this took me a while to piece together!

Rails and JavaScript: Can't add .erb extension

I have a JavaScript file called users.js and it is in app/assets/javascripts/users.js. I have it load in a single page using
<%= javascript_include_tag params[:controller] %>
I was thinking of using some Ruby code in the JavaScript file, so I changed the filename to users.js.erb. But when I do, the file shows up in my SublimeText project view as users.js.erb.js, and when I run my Rails app, I get a 404 error saying users.js.js couldn't be found.
Help? Thx.
From my perspective, this is not a rails problem, but a problem with the editor you use. Check the file information in finder with cmd-i and change it back to users.js.erb.

Ruby on Rails: How to transfer dynamic data from server to javascript?

RoR has controllers that render views. One day I wanted a controller not only to render a specific view, but also to run some javascript code using data from contoller (#product, for example) after rendering.
1. Inline javascript
So I went to my products/show.html.erb and wrote something like:
<%= javascript_tag "alert('#{#product.name} is just awesome!')" %>
2. Assets with server data
But we're all grown up boys and know about unobtrusive javascript, so I included some javascript files to my layout:
<%= javascript_include_tag "#{params[:controller]}/#{params[:action]}" %>
and then went to app/assets/javascripts/products/show.js.erb and wrote:
$(document).ready(function(){
alert('<%= #product.name%> is just awesome!');
});
But than I remembered that assets are being precompiled in production and continued to think.
3. HTML data attributes
Another way to pass some data to javascript is by using html5 data attributes in view files:
<div class="product" data-product-name="<%= #product.name %>">
Then in your asset you can write something like:
$(document).ready(function(){
$('*[data-product-name]').each(
alert($(this).data('product-name') + ' is just awesome!');
);
});
4. One more request to server
Anyway if you want to be able to cache your view files and assets, it seems as if the only way to transfer data to javascript is by using an additional Ajax request. I wonder if it is good practice to create a separate action that will send #product to client?
Can anyone say, what is the nicest way to send data from server to a javascript while rendering a view and why?

The Proper Way To Handle Ajax Response Loading with js.erb files in Rails

I am new to Rails but I come from PHP, in which it was almost always the case that whenever I have an HTML AJAX response, I can always load it in a container(any element) using jquery's .load()
I did that with Rails too, but recently came into another approach: use .js.erb files. Use getScript() to a controller action, then the js.erb file will respond to the js (ajax) request, the do the loading in the .js.erb file.
given general.js:
$.getScript(url, function(){});
given index.js.erb:
$('#products').html("<%= escape_javascript(render_cell :products, :index, {:products => #products})%>");
but this appears to be quite repetitive when I can do the loading in general.js! Fire an ajax request to this template that a controller has and load that in a container(I can use jquery .load()'s selector to just select the elements I want, and I can use an application_controller condition to not render the layout):
<ul>
<%= render_cell :products, :index, {:products => #products} %>
</ul>
Is there any way I can make more effective use of .js.erb files in this case?
Note: I had to use the 2nd approach because I am using twitter-bootstrap tabs. I initially used the first approach but I think the 2nd way is more "the Rails way". This is a learning project so why not? XD

Categories

Resources