Ajax and Json with Rails - javascript

I followed Hartl's Rails tutorial where he does Ajax using RJS and sending javascript in the response to be executed on the client side to edit the DOM.
But what do you do if you want just JSON sent in the response and not send javascript. This also means the javascript to manipulate the DOM should already be in the html file on the client. Is there a tutorial as good as Hartl's book on how to do this in Rails. Presumably it would use Jquery and some other stuff maybe that I've not heard of to make the code not be a million lines?

My best attempt at an answer is that it really depends on the scope and complexity of what you're trying to achieve. Generally, JSON shows up in views. If your application does not require you to dynamically retrieve JSON, that is, you can load it all when the view is initially rendered, then you can set an instance variable in your view's controller like so
#my_json = some_object.to_json()
Then, your instance variable is available in your view
<script type = 'text/javascript'>
var theJSON = <%= #my_json %>
</script>
Now, your data is available in the DOM, parsed nicely into JSON.
If your application requires you to dynamically retrieve JSON after the controller/view are loaded, then you should probably look into using AJAX to hit a particular controller's method that returns the JSON that you desire.
Here's a good RailsCast that can hopefully help you along your way Passing Data to Javascript

You should take a look at Ajax in Rails 3.1 - A Roadmap.

Related

Rails Remote JSON call blocking controller thread

I am doing an HTTP request against a remote API in my controller such as this:
#results= JSON.load(open("http://someendpoint/whatever.json"))
I am then rendering the contents of the response in my view by iterating over the structure provided in the response:
<% #results['result'].each do |result| %>$
This works 100% fine from a technical standpoint. The problem is that the initial JSON load in the controller appears to block the controller's thread (prior to rendering the page). There is additional information on the page that I would like to load quickly (i.e. without the controller thread blocking). Basically what I'd like to do is make the HTTP request asynchronously, and then render the JSON structure via callback. I can put the information in a partial if that would make things easier.
I can definitely use something like an XMLHttpRequest to concatenating the results of this (with interpolated HTML elements) into a string, and then just using DOM insertion methods to place the data into the view. So, I suppose my questions are this:
Is there a good way to do this asynchronously, for example by using a Javascript a callback to render a partial from a variable declared in an XMLHttpRequest? Is it bad to declare variables in the view and then render them in a partial? This just seems like bad design to me. I basically don't want to generate a long HTML string after an XHR request and inject it into the DOM because it seems 'sloppy'.
I appreciate your help.
Would it not be simpler to put #results in it's own controller action with it's own endpoint and load it via AJAX?

angularJS & web2py: calling python from ng/javascript/html

I'm using AngularJS (mainly the client side) and web2py (mainly the server side)together in an app.
I have an issue now.
At a point of the program, I use AngularJS to get some data from the client and these data are store in an AngularJS variable. I planed to use $http.post to submit these data to database directly, but it didn't work due to cross-orign problem.
Right now I'm trying to pass these data(they are in JSON format) back to web2py and let web2py insert these data to database.(similar to submitting a SQLFORM).
Is there anyway I could pass these data as an argument to an web2py function and invoke that function within javascript code?
Possible approach in my mind:
1) Since I could write python in html using {{}}, and I could write html in javascript, could I write python code within javascript using something like: document.write({{python code}}) ?
I tried this but whatever html I write it goes to a brand new html page. I also tried document.getElementById('testDiv').write("<p></p>"); But it doesn't work.
2)use ajax, I'm not familiar with ajax, any example will be really appreciated!
Any thoughts?
Thank you all!
ok so you got me lost for a second there, lets see if i got it right
1- angular as your frontend
2- python as your backend
3- you are rendering an html document in python and delivering it to the browser
4- since python template language uses {{}} as delimiter am assuming you changed the angulars delimiters too
either using ajax or reload you'll need to provide a python post handler script. that takes your data and makes the DB update. if this is going to be a pattern and you are going to be making AJAX CRUD operations, you should use angular resources ngResource if not a simple
$http.post(url,data).success(function(response){})
https://docs.angularjs.org/api/ng/service/$http#post
where url would be your form submission handler url.
if you where to use a form you'll need to set the target to an iframe hidden in your page and the response should a script tag that gets the scope pertinent to your controller and let him know the result of the operation. this is an old approach, but handy when it comes to send information to sites that don't allow CORS which by the way might be the solution to your problem, when storing data directly to your db, you might just need to enable CORS headers in your storage engine API and that should allow you to submit information even when coming from a different domain
After hours of struggles and countless google, here's my workaround solution:
Main problem: the data are stored in AngularJS but AngulatJS could not submit data to database through API due to cross-orign issue. But Web2py could submit data to database using sqlform.
My approach:
1.)When the user click the submit button, invoke 'ng-click="submitBtn()"'.
submitBtn() is a function of the ng-controller, which has access to the data.
2.)In submitBtn(), the function first write data into web2py's sqlform through
document.getElementById('inputId').value=$scope.data;
then the function click the sqlform submit button through
document.getElementById('submitBtn').click();
It took me a lot time to figure out those element ids of fields in web2py's auto-generated sqlform. The way to find them is using developers' inspect element tool in a browser and see the source code directly.
Hope this will help someone will face the same issue!

Bind dynamic JSON data to Knockout view model impossible

Ok, I've been wondering what I'm doing wrong with a Knockout web app I'm trying to put together.
Here is the code excluding the AJAX service with my MVC PHP interface.
my.js = namespace declaration that I use for my app
data.js = contains static data which works to load the data into the view (leftPanel.php)
appViewModel.js = call the functions that loads the data from PHP server and declare the view model.
So, basically, here is the issue:
I've an AJAX Service that works and get the data as show in accounts_JSON.txt and currencies_JSON.txt. The JSON is well formatted and in the text files, I've only added returns to make it easy to read.
In appViewModel.js, the "getCurrencies" and "getAccounts" methods are called and work properly: iterate through the JSON data and put it in the specified array.
Then, at the end of appViewModel.js, I log in the Chrome console each step because I can't find out why "my.app.data.currencies" and "my.app.data.accounts" are logged as empty when they are not (screenshot_chrome_console.png).
Those arrays are populated before the ko.applyBiddings so if I were to use "my.app.data.currencies" and "my.app.data.accounts" to populate the view, it should work but it doesn't. Only the static data "my.app.leftPanel.currencies.list" and "my.app.leftPanel.accounts.list" works.
What am I missing? I really can't see!
Thanks a lot for your help :)
Well, I've solved my issue :) Thanks to this post (from Irakli Nadareishvili).
My problem was definitely the loading method of the data retrieved via AJAX. Using Underscore to load the currencies and the accounts first and when, and only when all is loaded, filteredAccounts is loaded since I need the full list of accounts.
Here is the final and cleaned-up code in case anyone is interested or stumble on the same problem.
Happy coding to all!

Sending data from Ruby(rails) code to javascript/jquery

I recently started working on a project which involves ruby on rails/javascript/jquery. I am very new to all this. The part I am involved is like this. User clicks on a button. A dialog will open, where user will enter a term to search. With that term, I am will be constructing an URI by looking at an xml. Then I will do a REST call. The response will be a XML file. I will be parsing it and displaying data in the same dialog where user entered term to search.
I am using JQuery to create a dialog. And I am doing parsing and REST call part in ruby code (Helper class). I am not using models and controller for my part. Now I need to send data from helper method to erb file where I will be displaying data as a table. Output will be like this
string11 string12 string13
string21 string22 string23
string31 string32 string33
. . .
. . .
For now, in ruby code I have create 3 arrays for every column. I am not sure on how to send data from ruby to html/javascript. If there is better way to do this then let me know. For ex: instead of sending as 3 separate array, is it better to send as xml/json? Or any other suggestions will be really helpful. Mainly I am not understanding on how to send this data to the erb file. Thank you in advance.
Edit: Adding a sample code
Javascript/Jquery -
On button click, I want to call a ruby method in erb file
Ex: <%= getUserList%>
erb file is also having other javascript/html code to display other stuffs.
And in helper method I have getUserList method
def getUserList(search)
uri = create_url(search)
#doc = Nokogiri::HTML(open(uri))
//Doing parsing and other stuffs here
//creating 3 array as mentioned above which needs to be displayed
end
I want above arrays to be displayed. I am not sure on how to send these arrays to the erb file which invoked this method
In your controller:
def users
respond_to do |format|
format.js do
render(:js => "callback(#{#users.to_json});")
end
end
end
Use something like this in your HTML to call that:
<%= link_to_remote "get users", :url => { :action => "users" } %>
More information on rendering vanilla JavaScript from a Rails action: http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-vanilla-javascript
This example constructs JavaScript that calls a "callback()" function in your JavaScript code, with JSON data. Your callback function will receive a JSON string that will be easy to parse. You could also use to_xml to send XML if you really want, but parsing JSON is much simpler and faster.
You don't need a helper in this example because the JavaScript call that includes the data will come directly from your controller. There is no view template, so you don't need a helper. The best place for the code that gets the #users would be in a User model class. Not an Active Record model, just a plain model. The code that fetches the users from the remote REST API could possibly be a class method. (If you're feeling lazy then you could set #users with the REST API response right there in the "users" controller action. But that's not ideal use of Rails because the whole point of Rails is MVC.)
If you're using jQuery, then you could also use jQuery's getJSON() function so that your controller would send only the JSON data without using the callback: http://api.jquery.com/jQuery.getJSON/
Note that this is the simple kind of answer that you seem to be looking for, but this isn't really the best way to do this kind of thing for more complex applications. The best way to do this kind of thing at the moment is with something like Backbone.js. http://documentcloud.github.com/backbone/ With Backbone.js, you can define a "users" collection in JavaScript, set the REST URL of that collection (it can be a URL in your Rails app, which relays data from some other API) and then you simply call users.fetch() in your JavaScript to load the data. It's very similar to Active Record, but for the client site. It's better because it abstracts the process and allows you to update and delete records as well as simply listing them.

HTML that's both server-side and javascript generated - how to combine?

I'm usually a creative gal, but right now I just can't find any good solution. There's HTML (say form rows or table rows) that's both generated javascript-based and server-sided, it's exactly the same in both cases. It's generated server-sided when you open the page (and it has to stay server-sided for Google) and it's generated by AJAX, to show live updates or to extend the form by new, empty rows.
Problem is: The HTML generation routines are existing twice now, and you know DRY (don't repeat yourself), aye? Each time something's changed I have to edit 2 places and this just doesn't fit my idea of good software.
What's your best strategy to combine the javascript-based and server-sided HTML generation?
PS: Server-sided language is always different (PHP, RoR, C++).
PPS: Please don't give me an answer for Node.JS, I could figure that out on my own ;-)
Here's the Ruby on Rails solution:
Every model has its own partial. For example, if you have models Post and Comment, you would have _post.html.erb and _comment.html.erb
When you call "render #post" or "render #comment", RoR will look at the type of the object and decide which partial to use.
This means that you can redner out an object in the same way in many different views.
I.e. in a normal response or in an AJAX response you'd always just call "render #post"
Edit:
If you would like to render things in JS without connecting to the server (e.g. you get your data from a different server or whatever), you can make a JS template with the method I mentioned, send it to the client and then have the client render new objects using that template.
See this like for a JS templating plugin: http://api.jquery.com/category/plugins/templates/
Make a server handler to generate the HTML. Call that code from the server when you open the page, and when you need to do a live update, do an AJAX request to that handler so you don't have to repeat the code in the client.
What's your best strategy to combine the javascript-based and server-sided HTML generation?
If you want to stay DRY, don't try to combine them. Stick with generating the HTML only on the server (clearly the preferable option for SEO), or only on the client.
Make a page which generates the HTML on the server and returns it, e.g.:
http://example.com/serverstuff/generaterows?x=0&y=foo
If you need it on the server, access that link, or call the subroutine that accessing the link calls. If you need it on the client, access that link with AJAX, which will end up calling the same server code.
Or am I missing something? (I'm not sure what you mean by "generated by AJAX").
I don't see another solution if you have two different languages. Either you have a PHP/RoR/whatever to JavaScript compiler (so you have source written in one language and automatically generated in the others), or you have one generate output that the other reads in.
Load the page without any rows/data.
And then run your Ajax routines to fetch the data first time on page load
and then subsequently fetch updates/new records as and when required/as decided by your code.

Categories