I've made a Rails app using UJS and remote=true links.
For a controller#index action, instead of showing the content on page load, I'd like to call the #index action via Javascript once the page has loaded.
In short, I want to trigger the same functionality that is carried out when clicking a link like this:
<%= link_to "My Link", index_controller_action, :remote => true %>
But I want this to happen on 'page ready' rather than having to click the link.
Should I use the JQuery $ajax function for this? I have hacked it for now by triggering a false 'click' action on the remote link, but I'm sure this isn't best practice...
Related
I have a Rails 6 app where users can submit changes to a model and a confirmation email will be sent to site admins. The changes are submitted through a modal popup and once submitted the popup is replaced with another that confirms that the email has been sent.
The problem I am having is when this is done on a mobile device (I'm using an iPhone, not sure if this happens on Android), once the change is submitted another popup appears prompting me to download a file of size 0 with the name of the model being updated (it happens in both Safari and Chrome). This doesn't happen on the desktop version of the site or in the mobile emulator on the desktop, so I can't think of how I could diagnose this issue.
Here is the code being called just before the download popup appears:
<%= button_tag "Submit", type: 'submit',
id: 'modal-subimt',
class: 'btn btn-primary',
onClick: 'replaceModal()' %>
Here is the create function being called when the form is submitted:
def create
... # Setting the parameters for the model being changed
if #model.save
#model.send_confirmation_email()
else
# Irrelevant because the email gets sent
end
end
Here is the send_confirmation_email function being called in create:
def send_confirmation_email()
UserMailer.model_confirmation(self).deliver_now
end
And here is the model_confirmation function being called by send_confirmation_email:
def model_confirmation(model)
#model = model
recipient = <admin email>
mail to: recipient, subject: "Model Confirmation"
end
Nowhere in this code can I see where I might be prompted to download a file, but alas it is happening. Any help would be appreciated on how to properly diagnose or solve this problem. Thanks!
EDIT:
I changed my code so that the model would be updated without sending a confirmation email Also, the modal is no longer replaced with the new one verifying an email has been sent, and I am still having the same issue. This leads me to believe that the problem is something with the creation of the model.
EDIT 2:
Previously I was creating the model and remaining on the page (with the confirmation that the email was sent). I changed my controller to redirect_to request.referer to reload the page once the change is made, and when that is done I am no longer prompted to download the empty file. Unfortunately, the way I want this to work, reloading the page isn't optimal. Is there any reason that I would be prompted for a download when updating a model without reloading the page?
SOLUTION:
I was able to solve this problem by adding remote: true to the form_for line like the following:
<%= form_for(Model.new, remote: true) do |f| %>
...
<%= button_tag "Submit", type: 'submit',
id: 'modal-subimt',
class: 'btn btn-primary',
onClick: 'replaceModal()' %>
<% end %>
I'm not sure why exactly this solved my problem though so if anyone can provide some insight that would be much appreciated!
The problem is related to how you instantiated the form_for. When you submit the form to a Model.new object, form_for try to infer the controller with the create method for handling it. See more how form_for works in https://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
With that said, the create method is probably outputting something or nothing instead of redirecting, that's why you get a download on a mobile device and in browsers it's just an empty page because they can handle it. If there is no render on the method, Rails will answer with a 204 No Content or an empty text page. You must check your method about this.
When you use remote: true, I will quote from the docs:
:remote - If set to true, will allow the Unobtrusive JavaScript drivers to control the submit behavior. By default this behavior is an ajax submit.
So instead of reloading the page, UJS sends a XMLHttpRequest to the "backend" page, that's why you don't get a redirect. The result of the submit is treated without redirecting. But based on the result of the request the content of the page can come. So it's important that you give a response accordingly. In the links below you will find the right way to do it.
See more in these questions:
How does ':remote => true' works in rails
:remote => true confusion with form_for
Also, in the Rails Guides:
https://guides.rubyonrails.org/form_helpers.html
https://guides.rubyonrails.org/working_with_javascript_in_rails.html
This is also a good reference:
http://www.korenlc.com/remote-true-in-rails-forms/
I have a problem while making a back button for form in rails.
I have a dynamic form that looks like this:
dynamic form
However, when I press 'preview' button, the page will redirect to another page. In this page, I have created button:
<%= button_to 'Back to edit', 'javascript:history.go(-1);', {class:'btn btn-primary'} %>
It really back to previous form, but only 1 single form displayed
returned form
Can anyone can help me???
You can do this follow as:
<%= link_to 'Back to edit', :back %>
Most browsers will cache the back action and therefore won't issue an HTTP request to your server. If you need to display fresh data, then use a redirect via javascript's window.location rather than relying on the history state.
I've got my app working as I want it without AJAX.
I'm adding AJAX now to an item listing page with an 'add item' button.
Normally, clicking 'add item' it'd just go to the new item page, but with ajax it injects the new item form onto the page. On submit it updates the listing. This is all working fine, too.
However, if I visit the new item page directly, upon submitting the form it still fires the javascript. I want avoid any AJAX form submission if I'm on the form page itself.
Is it possible to only add remote => true to my form tag if the page has been requested through AJAX?
(...or suggest a better way to do this)
request.xml_http_request? will tell you if you are serving an ajax request:
<% if request.xml_http_request? %>
....
<% end %>
EDIT:
In addition to the helpful comments below, two excellent articles by Steve Schwartz explain everything clearly:
http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
http://www.alfajango.com/blog/rails-3-remote-links-and-forms-data-type-with-jquery/
Rails 3.2.2 / jquery-rails 2.0.1 (uses jquery 1.7.1)
I have link which sends an AJAX request to add additional file upload fields to a form. Everything page-related works correctly - the new form field HTML fragment is retrieved from the server and appended to a div inside the form.
However,
The server receives two GET requests. One is the AJAX request ; the other appears to be the "normal" anchor element GET. I expected the "normal" GET would be stopped by Rails UJS.
Am I supposed to disable the normal link action myself? Can someone please explain what I have misunderstood, and what I should be doing instead [to prevent the second request]?
I've seen this question: Rails 3 UJS - controller gets called twice by link_to :remote. Accordingly, I tried changing the asset pipeline compilation config.assets.debug = false, but it had no effect. Moreover, this is not a double-AJAX GET request, so I think it's a different issue.
Thanks for any help!
Server log snippet:
Started GET "/files/new?asset_number=2" for 127.0.0.1 at 2012-03-23 15:23:27 +0100
Started GET "/files/new" for 127.0.0.1 at 2012-03-23 15:23:27 +0100
Browser HTML:
Add another file
View:
<%= link_to 'Add another file', new_file_path, :remote => true,
:update => 'files',
:position => 'after',
:id => 'add_another_file' %>
Controller's coffeescript:
$( ->
$('a#add_another_file').click( ->
url = '/files/new?asset_number=' + $('#files input').length
$.get(url, ((data) -> $('#files').append(data)), 'html')))
If you're adding a click event to a#add_another_file , then you don't need to use :remote => true , because you're making the Ajax request manually.
Also, the click event should prevent the default action from occurring. This can be accomplished by adding event.preventDefault(); to the beginning of the click event's callback. Note that the callback needs to accept the event argument.
If you want to use the :remote => true option, you should remove the custom click event that you've added. This is because the :remote => true option tells the *jquery_ujs* library to hijack clicks on a#add_another_file. Thus, you needn't make your own HTTP request.
Next, to dictate what's done with the response, bind to the various events that will occur on a#add_another_file, such as success and error.
Here's the full list of Ajax events that you can bind to.
It's actually pretty simple, your remote link_to is sending one request (without params) and you've added a click event on that link to send another one (with params).
You should simplify your link_to as:
<%= link_to 'Add another file', new_file_path, :id => 'add_another_file' %>
Then in your click event you should return false so it doesn't follow the url.
It looks like you're using a lot of unnecessary parentheses in your coffeescript.
$ ->
$('a#add_another_file').click ->
url = '/files/new?asset_number=' + $('#files input').length
$.get url, ((data) -> $('#files').append(data)), 'html'
I want to execute a simple thing. When the user clicks the link jQuery needs to generate an Ajax request which sends the id of the link item to a method in the controller. Basically I want a nice looking modal dialog window when the user clicks the delete link. That window needs to contain various info about the deleted items.
E.g.
<%= link_to "Delete", item, :id => "delete" %>
I'm able to select this link with jquery and even to open a popup dialog when the user clicks it. Through application.js but what i really need is jQuery to call my method when the link is clicked and in my method I would answer via format.js. In the js file I place the code to show modal dialog with required parameters. All those actions asynchonous via ajax ofcourse.
I can't generate the ajax request to the method in the controller. Don't know already how to deal with the jQuery.ajax method, especially how to force jQuery to pass the url parameter to the rails method. I watched the railscast and studied the example with .post, but I don't need to submit any form.
Any advise is appreciated.
Thanks
Rails expects a post, with a hidden param.
$('#delete').click(function(e){
e.preventDefault();
$.post($(this).attr('href'), { _method: 'delete' });
});
Rails 3 has an unobtrusive way of doing this using a jQuery plugin:
http://github.com/rails/jquery-ujs
Once you have that loaded into your layout (with jQuery 1.4.1 or newer), you can do interactions like this pretty easily.
<%= link_to 'delete', item, :remote => true, :method => :delete,
:confirm => 'Are you sure?' %>
In Rails 3 all this does is add some HTML attributes to your link. These get caught by live handlers in the jQuery plugin. It's easy to use this behavior in a Rails 2 application, though:
<%= link_to 'delete', item, :'data-remote' => true, :'data-method' => :delete,
:'data-confirm' => 'Are you sure?' %>
Note that you need to have the jQuery plugin loaded in your view.
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
If you need the initial response to be a modal instead of an alert, you could make the first link a bit simpler:
<%= link_to 'delete', modal_confirm_item_url(item), :'data-remote' => true %>
You could link it to some pre-existing member action. Or since you may eventually want to use .js responses from those actions to serve other ajax requests, it may make sense to create a new action to handle this behavior.