Devise logout not working - javascript

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.

Related

Rails app sending javascript to client when loading whole page, but not when clicking link_to root_path?

When I refresh my Rails app or press enter on localhost:3000 in the browser, my app loads
'/' correctly and displays to the console
Started GET "/assets/*"
for all assets my app has to send.
But when I click a link which is produced from
link_to root_path
it displays the GET '/' in the console correctly, but it does not do a GET on all the assets,
thus causing all elements on the webpage which use my javascript to not work.
How can I remedy this?
Edit: Using rails version 4.1.6
Based on what limited information has been provided in the question, I believe that you are likely on Rails 4 and this is due to Turbolinks.
If you want to disable turbolinks you can follow the following steps
Remove the gem 'turbolinks' line from your Gemfile.
Remove the //= require turbolinks from your app/assets/javascripts/application.js.
Remove the two "data-turbolinks-track" => true hash key/value pairs from your app/views/layouts/application.html.erb.
Place = javascript_include_tag 'application' at the bottom of application.html
Place = stylesheet_link_tag 'application', :media => 'all' at the top of application.css in the head tag
These steps are outlined by Steve Klabnik here Removing Turbolinks from Rails 4
The following is not a direct answer to your question, but some additional elaboration on Turbolinks.
The intent of Turbolinks is to decrease page reload times by not requiring the browser to recompile the JavaScript and CSS between each page change. By default a new Rails 4 application is opted-in to this. Since the JavaScript is not reloaded on every request you can no longer use your standard DOMContentLoaded or jQuery.ready() methods of triggering your code.
Turbolinks fires supplemental events on document that you would need to opt-in to instead, such as page:load
For more complete information if you are interested in going this direction you can view additional details in the turbolinks github repo.

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?

jQuery Remotipart sending [object Object] to server

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.

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

Rails Asset Pipeline: Return digest version when non-digest requested

I am providing a snippet for a client to paste into their static html that refers to my application.js file.
As this sits on a page that I do not have control over, and I do not want to ask the client to update their snippet every time I push a release, I am wondering if there is a way to return my digest-application.js version when the normal one is requested to ensure that the browser is getting the the most recent version?
I can set a cache-busting timestamp on the script src, but not sure this is really reliable.
Any thoughts on the best way to handle this?
we are doing something similar for our "public" javascript, which is integrated into a 3rd party web-application.
the way we do this is by creating a symlink on our asset-server during the capistrano deployment that points to the non-digest name of the file. since they are just files on our webserver, the apache does the rest.
I think the must elegant way is doing some Controller to do some redirect 302 to you assets.
You can paste to your client a code link /public-assets/my_assets
In your route create the route :
match '/public-assets/:asset_name' => 'PublicAsset#index'
And create your controller PublicAssetController
class PublicAssetContoller < ApplicationController::Base
def index
redirect_to asset_path(params[:asset_name])
end
end

Categories

Resources