Rails - Make ajax request from javascript event and load partial - ruby-on-rails

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.

Related

Use Rails logic with JSON data

This may seem a pretty stupid question but I'm out of ideas at the moment and appreciate suggestions.
I have created a quiz interface that should change the question when NEXT button is clicked. The next question is loaded as JSON via AJAX call. Now the question contains HTML and I need to use Rails sanitize helper to filter tags.
I am not sure how I would use sanitize method on JSON data data acquired via AJAX call.
Please guide me.
EDIT:
The stress was not on JSON data. It was an honest mistake. The issue was the inability to use Rails logic on the data returned by AJAX call.
After some research and with the help of this answer, I was able to achieve what I wanted to.
All I had to do was to create a partial template (say, _question.html.erb) for the quiz question container with a form like this:
_question.html.erb
<%= form_tag('/question', :remote => true, :id => 'quiz') do -%>
... some code here ...
<%= submit_tag 'Submit' %>
<% end -%>
Create a route /question in routes.rb:
match 'question', :to => 'quiz#question', via: [:post]
and in QuizController.rb handle the response:
class QuizController < ApplicationController
def question
... some logic here ...
#ques = ...
#options = ...
respond_to do |format|
format.html
format.js
end
end
end
Now, create a question.js.erb to render the template with data:
$('#quiz-container').html("<%= escape_javascript(render partial: 'question',
:locals => { ques: #ques, options: #options }) %>");
The :remote => true option in the form does the trick here. It submits the form via ajax. Now, I can use Rails logic inside the partial template that gets the data via AJAX call.

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

Rails with jQuery + AJAX fundamentals

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.

How to use client side validation with remote => true rails 3.1

Normally we can use many ways to use ajax with validation like using validate plugin or using plain ajax(no rails ajax) like below
data using ajax requests
$.post("test.php", $("#testform").serialize());
In your situation it can be something like that.
$('#your_form').submit(function(event) {
event.preventDefault();
/* Email validation here.*/
$.ajax({
type: "POST",
url: $(this).attr('action'),
data: $(this).serialize(),
});
});
But, I wish to use client side validation with Real Rails ajax . Please help how to do this?
Maybe you'd like to use this gem
UPDATE 1:
Since you want to do this through ajax, validation can be handled through you controller.
# Let's assume your remote request hits index
def index
#object.create(params[:object])
respond_to do |format|
format.html # index.html.erb
format.js
end
end
Now, define an index.js.erb in the relevant views folder & render
<% if #object.new_record? %>
alert("Failed to upload record: <%= j #object.errors.full_messages.join(', ').html_safe %>");

Best way to get will_paginate working with Ajax

If you google "will_paginate" and "ajax", the top result is this blog post: But the original author of will_paginate says to not use this method (bad for SEO/spiders) ...
But I cant get the original authors method to work (his javascript kills all my links). An other gentleman suggests a similar method to mislav's (the original will_paginate author) concept. But I cant get that to work either.
so .... what is the best way to paginate using AJAX, and stay SEO friendly? (for RAILS >2.1)
Tomh's answer is correct. Just for shiggles, I prototyped a quick implementation. Here's a screencast that shows it using Ajax when Javascript is enabled (your users) and still having pretty URLs when Javascript is disabled (Google). And here are a few code snippets to get you rolling on it.
config/routes.rb:
map.connect 'items/:page', :controller => "items", :action => "index", :page => 1
app/controllers/items_controller.rb:
class ItemsController < ApplicationController
def index
#items = Item.paginate(:all, :page => params[:page])
respond_to do |format|
format.html
format.js do
render :update do |page|
page.replace_html :items, :partial => "items"
page << "ajaxifyPagination();"
end
end
end
end
end
app/views/items/index.html.erb:
<h1>Listing items</h1>
<div id="items">
<%= render :partial => "items" %>
</div>
app/views/items/_items.html.erb:
<%= will_paginate #items %>
<table>
<% for item in #items %>
<tr>
<td><%= item.id %></td>
</tr>
<% end %>
</table>
layout:
<%= javascript_include_tag :defaults %>
public/javascripts/application.js:
$(document).ready(function() {
ajaxifyPagination();
});
function ajaxifyPagination() {
$(".pagination a").click(function() {
$.ajax({
type: "GET",
url: $(this).attr("href"),
dataType: "script"
});
return false;
});
}
My example uses jQuery (with jRails), but it's straightforward to do with Prototype as well.
Seo friendly and unobtrusive javascript goes hand in hand. What you can do is the following.
Code the entire site as if only html is enabled (incl your pagination thing)
Use respond_to and serve only the list of items if the request comes in from js
Using onDomReady from whatever library you pick you attempt to catch all pagination links and add an onclick event which triggers an ajax call to that new view and returns the result. You put that result into the container containing the data you are paginating. The onclick then returns false.
To give your users a better user experience you can add some features like active links etc to the same javascript method.
Using this approach the pagination will work for JS and non-js as the non-js users (including Googlebot) will traverse your pagination as normal. Only in the event that the user has javascript enabled, the container with data will be updated with new results.
Unfortunately, I don't think you can use Ajax in the way you want and still stay SEO friendly as far as the paginated content. The problem is that the robots of Google and friends, as far as I know, won't go through your content using XHR requests so they simply won't see that content.
That said, if the paginated items each have their own static, SEO-friendly pages (or are otherwise statically available on your site), the content will still find its way into their engines. This is the way you'll probably want to go.
There is a railscasts on this topic which helped me out http://railscasts.com/episodes/174-pagination-with-ajax
I'm running rails 3.2, so I added the pagination.js there mentioned to app/assets/javascripts folder
pagination.js
$(function() {
$(".pagination a").live("click", function() {
$(".pagination").html("Loading...");
$.getScript(this.href);
return false;
});
});
And then created
home.js.erb
$('#div_tags_list').html('<%= escape_javascript(render partial: '/customersb2b/user_customer_numbers_list').html_safe %>')
$('#receipts_list').html('<%= escape_javascript(render partial: '/customersb2b/feed').html_safe %>')
Since I have two distinct listings on my homepage.
This is all I had to do to put will_paginate working with Ajax.
As for the SEO concerns, well, I don't know much about it, but the URL http://localhost:3000/customers?_=1366372168315&feed_page=1&tags_page=2 still works
There is a great way to do this easily if not worried about spiders. Took me 5 minutes. Check out:
https://github.com/ronalchn/ajax_pagination/wiki/Adding-AJAX-to-will_paginate
If you get an error about a missing 'history' file, install:
https://github.com/wweidendorf/jquery-historyjs
but also be aware of:
rails ajax_pagination couldn't find file 'history'

Resources