By default rails (I am using rails 4) sends data-remote requests with the following header:
Accept:*/*;q=0.5, text/javascript, application/javascript, application/ecmascript, application/x-ecmascript
Later in rails code I respond to it using format.js.
I want to migrate to wiselinks, but all data-push requests try to render html.
Is it possible to have default rails behaviour with wiselinks?
I think that you don't unserstand correctly how Wiselinks work. If you use :data => { :remote => true }, then you simply don't need :data => { :push => true }.
Pushing should be used only if you need to update your URL (follow a link).
Ok, I rewritten my controllers to respond to html AJAX requsets instead of using JS requests.
This way I can use wiselinks and it works. Main reason I was using JS response is to set page title with javascript and some other details. But with wiselinks I can use special helper for that.
I think there may be a need in the future to implement some complex behaviour after AJAX request, which will require some JS execution on client side after the response. However this will be possible to implement with page:done event
Thank you all for the help!
Related
If I send a remote: true request to our subdomain controller, our layout renders (which it shouldn't)
Having tested the request.xhr? method in the action, it's returning nil (not the true / false) that you'd expect. This works for non-CORS ajax. It only stops working with CORS-ajax (for subdomain)
Here's the code:
#app/views/controller/view.html.haml
= link_to "test", new_user_session_url, remote: :true
#routes
new_user_session_path GET /login(.:format) admin/users/sessions#new {:subdomain=>"test"}
The response occurs & we get a layout
We want no layout, which works without CORS:
#app/controllers/application_controller.rb
layout :layout_select
def layout_select
if request.xhr?
false
else
devise_controller? ? "admin" : "application"
end
end
We have CORS policy set up & working. However, it seems our CORS-request is not being treated as xhr. Any ideas?
In light of the comments from Mike Campbell, I was able to determine that CORS requests are not treated as ajax (xhr) by default
The problem lies in the headers which are passed on an Ajax request. Standard ajax passes the following header:
#actionpack/lib/action_dispatch/http/request.rb
def xhr?
#env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/
end
This is passed with a "naked" Ajax request, which allows the xhr? method to return either true or false. The issue is in a CORS ajax call, this header is not passed. I don't know why, but it just sends an ORIGIN header instead
The proposed fix from Github suggested to include this:
uri.host != #env['HTTP_HOST'] || uri.scheme != #env['rack.url_scheme'] || uri.port != #env['HTTP_PORT'].to_i
This would basically return a boolean response based on whether the request was from the same domain as the script. Although this was prevented for being unsafe, it lead me to two fixes:
Append a new cors? method to the Rails core
Send the http_x_requested_with header through a CORS request
Considering we are just trying to access a subdomain with the request, we felt that editing the Rails core was slightly overkill, although right. Instead, we found that using the inbuilt headers argument in jquery would help:
$.ajaxSetup({ headers: {"X-Requested-With": "XMLHttpRequest"}});
Whilst this works, I am eager to hear about any security issues it may present. And plus, whether we can access json and other formats with it
It's because of the Same-Origin Policy. Please read carefully this article: HTTP access control (CORS).
The possible solutions are:
make simple request – instead of remote: true do usual form post or maybe $.getJSON() will work (not sure).
implement preflight request – you'll need to implement on your server response for OPTIONS request.
if you need to maintain cookies then you'll also need to write custom ajax code, eg. $.ajax({url: a_cross_domain_url, crossDomain: true, xhrFields: {withCredentials: true}}); and return some specific headers from the server.
So, I'm having issues with what I think is a really simple problem. I don't know how to access user input...or perhaps I don't know how to declare a temporary variable in rails.
Anyway, what is the most straight forward way of accomplishing this:
<div>
Enter Group Size: <%= number_field_tag(:group_size)%>
Select Study Site: <%= number_field_tag(:site) %>
</div>
<% if :site > 4 %>
Hello!
<% else %>
Nope!
<% end %>
I suppose I'll need javascript to actually make it work, but for now I just need to know how to use these variables.
Any help would be greatly appreciated. Thanks.
To use them dynamically with ERB, they need to be wrapped in a form and submitted to the server. You can then access them easily with params[:variable_name]. It would probably be cleaner to prepare the message in the controller, but if you don't need to interact with models, it would be more straightforward to use some basic JS to do everything.
As with most things, the solution is a lot more involved:
Ajax
Unlike native apps, Rails relies on the HTTP protocol
HTTP works on requests. You send requests to a server to render a web page; the server responds to the requests. The problem with this is you cannot use Rails with "live" functionality without sending requests to-and-from the server (even "live" applications just keep a perpetual connection open, acting as a single request)
This means if you want to process "live" data (without refresh), you'll have to use a technology to send a request on your behalf. As you noted, this will be ajax:
$(".element").on("action", function(){
$.ajax({
url: "your/end/point"
data: {your: data}
success: function(data) {
alert(data)
}
});
});
Rails
To handle an ajax request in Rails, it's basically the same as handling an HTTP request:
#config/routes.rb
resources :controller do
get :your_endpoint
end
#app/controllers/controllers_controller.rb
def your_endpoint
# perform actions here
respond_to do |format|
format.html
format.js { # handles JS / Ajax request }
end
end
Return
You can then handle the returned data with your JS (Ajax) function. This gives the image that it's working in "real time", but will actually be sending & receiving requests from the server every time
I'm building a client side application which cross-domain posts JSON, using CORS, to a Rails 3.2 application on a different server. Unfortunately, we need to support IE9, which means that we're falling back to using XDomainRequest (XDR) to send our cross-domain requests in IE.
The major limitation of XDR is that it doesn't support setting headers like 'Content-type', which means the Rails server doesn't know that it's receiving JSON, so doesn't parse it.
I got around this briefly by using jQuery.param to send the data as url encoded form data. However, some of the data we need to send is nested GeoJSON, which gets garbled by jQuery.param, so I have to send the POST body as JSON.
In config/initializers/wrap_parameters.rb I've set:
ActiveSupport.on_load(:action_controller)
wrap_parameters format: [:json, nil]
end
… so ActionController nests parameters inside model_name when the content-type is nil.
However, I still need Rails to try to JSON.parse() the data from requests where "Content-type" => nil. I could just manually do this in the controllers which need it (which isn't very clean), but I was hoping I would be able to make Rails do it for all {content-type: nil} requests.
I've been looking through the Rails source, and what I've found doesn't make me very hopeful. This method seems to be hard coded to check for :json, and parse if so, meaning I can't modify this from config:
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/params_parser.rb#L43
Can anyone come up with a clever solution?
I'm working on a project that makes heavy usage of XHR, and there is some data that needs to be appended to each ajax request in order for the server side to properly keep track of what is going on in the browser.
I have a generic class called xhr_response_handler than I use to handle the callbacks for all ajax requests that is added to all forms, links etc that is making ajax requests. (i.e. where ":remote => true" in rails)
$('.xhr_response_handler')
.on('ajax:success', function(event, data, status, xhr) { xhr_success(data); })
.on('ajax:failure', function(xhr, status, error) { xhr_fail(error); });
Then I try to append the default data sent with each request using:
$.ajaxSetup({
data: {
Foo: <%= #Bar %>
}
});
This works for some of the elements where the ajax settings are configured directly with jquery, but this does not work for some elements created using rails methods like link_to and form_for with :remote => true.
The odd thing is that if I also add
$('.xhr_response_handler').data( 'params', { Foo2: <%= #Bar2 %> } );
Then that works for adding data to the rails generated ajax requests using link_to. What makes it odd is that now all of a sudden the ajaxSettings also works, and in the ajax requests I get both Foo and Foo2 as parameters. But I get no parameters at all when using ajaxSettings by itself.
Furthermore, none of the data to be appended gets serialized into the form data sent in ajax requests generated from the rails form_for method.
Any help would be appreciated.
Rails 3.2.3
Ruby 1.9.3p194
jQuery 1.7.2
I think this behaviour appears because the data hash of $.ajaxSetup is overridden by the ajax calls you do later on. The data has to be merged manually.
I'd like to create a link in a view within a Rails application that does this...
DELETE /sessions
How would I do that.
Added complication:
The "session" resource has no model because it represents a user login session. CREATE means the user logs in, DESTROY means logs out.
That's why there's no ID param in the URI.
I'm trying to implement a "log out" link in the UI.
Correct, browsers don't actually support sending delete requests. The accepted convention of many web frameworks is to send a _method parameter set to 'DELETE', and use a POST request.
Here's an example in Rails:
<%= link_to 'log out', session_path, :method => :delete %>
You may want to have a look at Restful Authentication.
I don't know about Rails specifically, but I frequently build web pages which send DELETE (and PUT) requests, using Javascript. I just use XmlHttpRequest objects to send the request.
For example, if you use jQuery:
have a link that looks like this:
<a class="delete" href="/path/to/my/resource">delete</a>
And run this Javascript:
$(function(){
$('a.delete').click(function(){
$.ajax(
{
url: this.getAttribute('href'),
type: 'DELETE',
async: false,
complete: function(response, status) {
if (status == 'success')
alert('success!')
else
alert('Error: the service responded with: ' + response.status + '\n' + response.responseText)
}
}
)
return false
})
})
I wrote this example mostly from memory, but I'm pretty sure it'll work....
Correct me if I'm wrong, but I believe you can only send POST and GET requests with a browser (in HTML).
Rails' built in method for links will generate something like this:
Logout
If you don't want to use the Rails' built in method (i.e. don't want the rel="nofollow", which prevents search engine crawlers from following the link), you can also manually write the link and add the data-method attribute, like so:
Logout
Browsers can only send GET/POST requests, so this will send a normal GET request to your Rails server. Rails will interpret and route this as a DESTROY/DELETE request, and calls the appropriate action.