Rails with jQuery + AJAX fundamentals - ruby-on-rails

I've been given a task to do a simple Task Manager on Ruby On Rails. It's pretty simple for me but there is one issue. Everything has to be "ajaxified" and data should be passed around in JSON.
How I do this right now.
On index.html.erb
I'm creating a simple form with these parameters:
<%= form_for(Task.new, remote: true, :html => {:'data-type' => 'json'}) do |f| %>
In TasksController:
class TasksController < ApplicationController
respond_to :json
def create
#project = Project.find(params[:task][:project_id])
if #task = #project.tasks.create!(name: params[:task][:name], description: params[:task][:description])
respond_with(#task)
else
flash[:error] = 'error'
end
and inside on index.htm.erb I have:
$(document).ready(function(){
$("#new_task").bind('ajax:success', function(evt, data, status, xhr){
var row = ('<tr id="task.id"><td>'+data.name+'</td>'+'<td>'+data.description+'</td>'+'<td>'+data.state+'</td>'+'<td><%= link_to "delete task", task_path(task.id), :method => "delete", remote:true, data: { confirm: "Are you sure?" } %></td></tr>');
$(row).insertAfter("#tasks_table tr:first");
slicer($("#total"));
slicer($("#active"));
}); });
$("#new_task").bind("ajax:beforeSend", function(event,xhr,status){
$(this)[0].reset();
});
And now I'd like to give some explanation about how this might work(my personal thoughts)
by specyfing remote: true, I'm telling the form to submit data in input on server via Unobtrusive Javascript, rails 3 feature. It sends an usual hash in my example this is params[:task][:name] etc, but it expects to get back JSON because I did set :html => {:'data-type' => 'json'}) (is this correct syntax?). Now in my TasksController class I have the respond_to :json, it means that controller WILL answer those requests, where data-type json is specified, with json, because respond_with is smart enough to do to_json on object you are doing respond_with.
Am I right in all those assumptions?
So the question is if we can use js.erb and json.erb(yes?) do you need to return the json at all ?

Maybe going a step back helps.
With AJAX form, the submit event goes through JavaScript first, and does not trigger the browser to invoke a POST '/data.json'.
If you look at the HTML that is generated by Rails with the remote: true option, you probably see a "onsubmit()" or similar callback. It is also the JavaScript, that processes a 'success' or 'error' event. I like the jQuery documentation for this: http://api.jquery.com/jQuery.ajax/
Your question is also somewhat opinionated, because JavaScript libraries such as Backbone.js, Ember.js or Angular, allow to fine-tune the process chain of a form submit even further.

Related

Rails form submission not happening in the background

I have a Rails 5.2 app, where I'm using form_with, which is generating this HTML:
<form id="post-0" class="" action="/posts.js" accept-charset="UTF-8" data-remote="true" method="post">
The form is submitting successfully to the PostController's create action.
def create
#post = current_user.account.posts.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to posts_path, notice: 'Post added.' }
format.js { render :create, status: :created }
else
format.html { render :index }
format.js { render :create, status: :unprocessable_entity }
end
end
end
It is then rendering the JS view:
app/views/posts/create.js.erb
alert('created');
However, in my browser, I'm literally redirected to http://localhost:3000/posts.js where it shows the javascript code. Meaning, the form submit doesn't seem to be happening in the background.
I would have expected to still have stayed on the page the form was on, with a Javascript Alert appearing saying "created".
Is there's something silly I've missed? Seems to me it must be something with form_with that I'm not doing right.
I tried swapping it for form_for #post, remote: true, format: :js do ... but that had the same problem.
At this point, I can't tell if the problem is in View that shows the form, or in the Controller's create action. The controller is rendering create.js.erb and the URL shown is http://localhost:3000/posts.js which does seem to suggest it's a Form problem in the View.
This app is Rails 5.2. I'm not sure it's relevant, but I've removed the Asset Pipeline for Webpacker, I do have rails-ujs installed (as it is showing the confirm dialog in these link_to links as expected <%= link_to('Destroy', user, method: :delete, data: { confirm: 'Are you sure?' }) %>
Form submissions can occur locally (ie. not remote) due to a number of reasons.
Some common reasons local submission may be occurring when using form_with include:
local: true
The local attribute is optional for form_with. If not provided, form_with will by default set local: false.
true will set the form to be submitted locally (standard form submission), not remote/asynchronously.
false will set the form to be submitted remotely/asynchronously.
Any value other than false (including :false which is a symbol not a boolean) will be interpreted as the value being true (ie. submit locally).
Javascript triggered form submissions
Despite the setting of the local attribute being set to something that should trigger a remote/asynchronous form submission, the form may still be submitting locally if you're triggering the form submit event via Javascript.
In the example given in question, the HTML generated by the form_with use is as expected, so attributes provided to form_with are not the problem in this instance.
If javascript is being used to submit the form, that could be the problem. For example, even with data-remote="true" on the form, this javascript will be a problem:
document.getElementById('form-0').submit();
This submits the form, but doesn't raise a submit event for rails-ujs to intercept via an onsubmit event handler.
Working with the Rails Unobtrusive Javascript Adapter
To have the form submission triggered by javascript (whether you're using jQuery, Stimulus JS, or anything else) you need to use a mechanism that rails-ujs (or jquery-ujs) will intercept for you.
Rails provides the Rails.fire custom javascript event wrapper in rails-ujs, which can by used like this:
Rails.fire(document.getElementById('form-0'), 'submit');
You're doing a very basic mistake. By using ajax you can't use format.js. This Ruby Module is used to redirect the page. instead you should be using render json: { status: 200}
saw your job on Upwork. No need to spend $100 on this!
<%= form_with url: content_export_path, method: :post, id: 'ce_form1', data: { remote: true } %>
Look where the remote: true declaration is... (inside data hash)
Let me know if this works.

How to implement ajax in rails 4.0 for a simple multiplication operation?

I am a beginner to rails.
What I'm trying to implement is simple:
I have two textboxes on the screen.In textbox1, I type in a number and click on the submit button.This submit button should perform an ajax request and then return a 'template' html which allows me to display the square of the number in textbox2.
Please help in understanding the naming conventions for the template/partial which is to be displayed when the ajax request is made
I know this question sounds incredibly dumb but rails is a tough framework to learn for a person who is a beginner to web development and I was unable to find a single tutorial on the internet which does this simple functionality. All the existing tutorials focus on retrieving data from the database which increases complexity and leaves me even more confused. The more I learn about rails, the more I realize that there is a lot more to learn.
I would appreciate detailed instructions on how to perform this task. If you feel that this question should be closed then please redirect me to some website where beginners are allowed to post questions.
You could do this with standard JS, like this:
#app/assets/javascripts/application.rb
$(document).on("submit", "form", function(e) {
e.preventDefault();
val = $("#textbox1").val();
square = val * val; // surely a function for this
$("#textbox2").val(square);
});
If you wanted to use Ajax, you'd do this:
#app/assets/javascripts/application.js
$(document).on("submit", "form", function(e){
e.preventDefault();
$.ajax({
url: "your/endpoint",
data: $("#textfield1").serialize(),
dataType: 'json',
success: function(data) {
$("#textfield2").val(data);
}
});
});
#app/controllers/your_controller.rb
Class YourController < ApplicationController
def action
#return = params[:textfield1]
respond_to do |format|
format.json { render json: #return.to_json }
end
end
end
You can just use the remote: true parameter
<%= form_tag action: '/calculate', method: :post, remote: true do %>
<%= text_field_tag 'x' %>
<%= text_field_tag 'y' %>
<%= submit_tag 'calculate' %>
This will render a form that will fetch it's result in ajax, of course substitute the letters with actual paths in your application.
You can then return javascript that does the rendering of the template

how to send remote form params

I have a form which is using several input fields being ajaxified with remote: true and custom controller actions. This way UJS driver sends only given form input as params. What I want to accomplish is an ajaxified input field which will send value of a field outside of it's "scope" as params. What do you suggest?
Let me explain the whole flow of the ajax-rails and remote=> true and you can do this with that following way and you can get all the params in your method.
first when you used the remote=> true then the form will submit or call the action which you have define in form like here is an example:
<%= form_tag({:controller => 'my', :action => 'my_data'},:id => 'filter_form', :remote => true) do %>
#code here
<%= submit_tag 'save', :name => 'commit'%>
<%end%>
now above code will go to my_data action in my controller,
here you can define the respone type with
def my_data
#actions on data here
respond_to do |format|
format.js
end
now you have to made a .js file with named as action name....
my_data.js.erb
here the whole affect of form you can write and update document element through jquery and javascript.
For every input you just assign a class and write a method that call when the input box will change.One more thing that when you wants to do in a single method the every input have a unique ID, send that also in params and do task what ever you wants to do.
Rails' JQuery UJS is just a dependency which Rails uses to call ajax requests on your behalf. This means your question is not particularly to do with JQuery UJS, but with how to handle it with ajax overall
You'll typically handle any extra data by appending it to the Ajax request:
<%= link_to "Link", new_post_path(params: "here"), remote: true %>
If you want to create an "ajaxified" field, you'll probably have to use a manual ajax call to capture the change event, allowing you to send the data to your event:
#app/assets/javascripts/application.js
$('input[name="element"]').on("change", function(){
$.ajax({
url: "url",
data: $(this).serialize()
});
});
Then, as mentioned by #baharat Soni, you'll be able to handle the request on the server using respond_to

Rails - Make ajax request from javascript event and load partial

what's up?
I'm using rails 3.2.3 with ruby 1.9.2p290.
I have a model Purchase which has many purchase_payments:
class Purchase < ActiveRecord::Base
has_many :purchase_payments, :class_name => 'PurchasePayment', :dependent => :destroy
accepts_nested_attributes_for :purchase_payments
def Purchase.build_payments(count)
#Creat #count payments with some logic for each of them
end
end
In my form, I have number_field:
<td>
<%= f.number_field :payments_count, :min => 0 %>
</td>
Now, I'd like to have the purchase_payment fields appear based on the number of payments. For that, I have a specific div:
<div id="purchase_payments_space"> </div>
Every resource I've found so far, talks about ajax generated by helper tags, like link_to ... , :remote => true, but using this tags, the user would have to click on the link to have the remote function called. In other part of my app, I use jquery ajax request and I'm trying to use like this for sending the request to my controller:
function load_payments() {
$.ajax({
type: "POST",
url: "/purchases/build_payments/" + document.getElementById("purchase_payments_count").value,
});
}
$(document).ready(function() {
$("#purchase_payments_count").change(load_payments);
}
In my controller, I have the respond_to :js right after my class declaration and the following method:
def build_payments
pc = params[:payments_count].to_i
#purchase = Purchase.new
#purchase_payments = Purchase.build_payments pc
respond_to do |format|
format.js
end
end
This way I have my app/views/purchases/buid_payments.js.erb run ok.
The thing is, I'm building a collection of payments that should be included in my form, and doing things the way I'm currently doing doesn't look like rails would do this. This way I will have to write much code in the js.erb file and still I can't figure out how I'll make the create method build the complete purchase from the params (I don't know how to build the form from the javascript).
I looked at several different ways but none have given an integrated solution for making an ajax request from a javascript event and have the view create the nested fields for my nested attributes (its a collection of purchase_payment I must remember).
I saw http://railscasts.com/episodes/196-nested-model-form-part-1 and http://railscasts.com/episodes/197-nested-model-form-part-2 but those build on top of helper methods like link_to and link_to_function.
Can anyone point me how can I accomplish that?
$.ajax({
url: "purchases/build_payments",
type: 'POST',
data: $('#purchase_payments_count').val(),
dataType: 'html',
headers: {
'X-CSRF-Token': '<%= form_authenticity_token.to_s %>'
}
});
then
def build_payments
pc = params[:payments_count].to_i
#purchase = Purchase.new
#purchase_payments = Purchase.build_payments pc
respond_to do |f|
f.js {}
end
end
which will run buid_payments.js.erb which can populate\recreate your table
If can't see it I can't help you.

Rails controller not rendering correct view when form is force-submitted by Javascript

I'm using Rails with jQuery, and I'm working on a page for a simple site that prints each record to a table. The only editable field for each record is a checkbox. My goal is that every time a checkbox is changed, an ajax request updates that boolean attribute for the record (i.e., no submit button).
My view code:
<td>
<% form_remote_tag :url => admin_update_path, :html => { :id => "form#{lead.id}" } do %>
<%= hidden_field :lead, :id, :value => lead.id %>
<%= check_box :lead, :contacted, :id => "checkbox"+lead.id.to_s, :checked => lead.contacted, :onchange => "$('#form#{lead.id}').submit();" %>
<% end %>
</td>
In my routes.rb, admin_update_path is defined by
map.admin_update 'update', :controller => "admin", :action => "update", :method => :post
I also have an RJS template to render back an update. The contents of this file is currently just for testing (I just wanted to see if it worked, this will not be the ultimate functionality on a successful save)...
page << "$('#checkbox#{#lead.id}').hide();"
When clicked, the ajax request is successfully sent, with the correct params, and the action on the controller can retrieve the record and update it just fine. The problem is that it doesn't send back the JS; it changes the page in the browser and renders the generated Javascript as plain text rather than executing it in-place.
Rails does some behind-the-scenes stuff to figure out if the incoming request is an ajax call, and I can't figure out why it's interpreting the incoming request as a regular web request as opposed to an ajax request.
I may be missing something extremely simple here, but I've kind-of burned myself out looking so I thought I'd ask for another pair of eyes. Thanks in advance for any info!
In your controller you need to specify the proper response. Since you didn't post the controller I'll just try to fill in the blanks.
def update
# Update something
respond_to do |format|
format.js # this renders your rjs file
end
end
Specifying the format tells the rails app to interpret the javascript instead of just sending it back as text.
The other option instead of using rjs is to do an inline rjs block like this:
render :update do |page|
page.replace_html 'user_list', :partial => 'user', :collection => #users
page.visual_effect :highlight, 'user_list'
end
Only use the inline rjs if you will be doing minimal changes to the interface that can be put into one or two lines. Anything more should be in it's own rjs file.
This question is related to this one, but the answer varies slightly. I had to create a new way to submit the form, since the default jQuery submit() method does not submit as a 'script' and certainly does not fire the code that Rails generates in the onsubmit="..." handler via the form_remote_tag helper.
The solution was to create a new function as the linked answer suggests, but the contents are slightly different:
jQuery.fn.submitWithAjax = function() {
jQuery.ajax({data:jQuery.param(jQuery(this).serializeArray()) + '&authenticity_token=' + encodeURIComponent('<%= form_authenticity_token %>'), dataType:'script', type:'post', url:'/update'});
return false;
};
This is brittle right now-- notice that I insert rails' form_authenticity_token into the Javascript, but really the method (post) and the url (/update) should also be generated rather than hardcoded.
Things are working A-OK now.

Resources