I'm trying to incorporate d3.js into my project and am having trouble figuring out how to access a JSON object, which is being served from my Ruby on Rails backend.
Here is my Controller code:
class CoursesController < ApplicationController
respond_to :html, :json
def course
#course = Course.find(params[:id])
respond_with #course do |format|
format.html
format.json {render json: #course}
end
end
I've been trying both in the console and in my view to figure out how to access the information. (by the way, if I scrap the respond_with block and just keep the render JSON block, I can see that the JSON object is, in fact, a response object).
Here is what I've been trying (in the view):
<%= javascript_tag do %>
var data = d3.json('<%= #course %>');
console.log(data);
<% end %>
This returns an object, but the object is undefined, so when I call:
dataset[0].course.course_name;
I get the following error:
TypeError: Cannot read property 'course' of undefined
I've also tried something like the following in the console:
var url = '/courses/1';
var dataset = d3.json(url);
dataset[0].course.course_name;
But get the same error.
I'm relatively new to js, so I'm likely making a rookie mistake, but, whatever it is, I can't see it!
Thanks in advance for the help!
The issue is that the d3.json function (https://github.com/mbostock/d3/wiki/Requests#wiki-d3_json) with one parameter returns the request. You would then have to issue that request.
The 'typical' use is to have a second parameter, with a callback function. This is an asynchronous callback, so you can't assign the return value to a var.
Here is what I suggest:
var url = '/courses/1';
d3.json( url, function( error, data ) {
console.log( data );
// do all actions required now that the data is retrieved
} );
Related
SPA html/JavaScript Rails app with a json API BackEnd to serve up data to the Front. The index page is displayed and built entirely with JS in a javascript_pack_tag. I then both call my own api for json data saved in PG and then to a third party API openweathermap. Everything was working just as I wanted then I attempted to store my openweathermap API key with the gon gem. I was able to do this. However it broke my app. I then undid all of the gon gem stuff and it the app is still broken.
Error
terminal
#ubuntu terminal
ActionController::UnknownFormat (CitiesController#index is missing a template
for this request format and variant.
request.formats: ["application/json"]
request.variant: []):
console
#chrome console
class_mode.js:238 GET http://localhost:3000/cities.json 406 (Not Acceptable)
fetchCityData # class_mode.js:238
(anonymous) # class_mode.js:9
localhost/:1 Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
#class_mode.js
line 238> return fetch(BASE_URL).then(res => res.json()).then(function (json) {
From these errors I have traced this back to my controller action returning HTML instead of JSON. Specifically the < indicates html returning in the controller.
Latest attempt to fix in controller
def index
#all = City.all_in_json
respond_to do |format|
format.html { render :index }
format.json { #all }
end
end
I also moved the json logic into the City model as such
def self.all_in_json
#cities = self.all
#returnValue = #cities.map do |city|
if city[:name] === nil
city[:name] = city.to_name
city.save!
city
else
city
end
end
#returnValue.to_json
end
Again this app was working perfectly. I have spend a full day of debugging now and am turning to StackOverflow.
I have attempted to create distinct routes to call my fetch() request to for the retrieval of all the records of the City table/ tried respond_to.
Your controller action does not say what to render, it simply calls the #all variable. Assuming you're correctly asigning #all to a json string, then try changing your controller method it:
def index
#all = City.all_in_json
respond_to do |format|
format.html { render :index }
format.json { render json: #all, status: 200, message: 'bla' }
end
end
Status and message are optional
Let's assume I have a Users controller with a returnjson action. Say I want to create an API so when the client calls on that method, it would return the user's data to the client. For example:
https://www.example.com/returnjson?username&password
A get request would be made by JavaScript with that URL and than the rails would than return the user info in a JSON format. How would I got about doing this?
Thanks in advance!
Oh i see, you only want to return the attributes requested in the parameters. Sorry.
First of all, i would just us the show action for this rather than making a new action. The purpose of show semantically is to return data for a single record, so it's the right action for this job.
Your parameters for the request aren't well structured - i would structure them like
https://www.example.com/users/123?required[]=username&required[]=password
which would give you
params = {:required => ["username", "password"]}
I would do it like so:
def show
#user = User.find_by_id(params[:id])
respond_to do |format|
format.html #default to standard 'render the show template'
format.js #default to standard 'render .js file' or whatever
format.json do
#filter out the ones we want
if params[:required]
hash = #user.attributes.slice(params[:required])
else
hash = #user.attributes
end
#this will automatically call `.to_json` on the thing we pass to it (`hash` in this case)
render json: hash
end
end
end
You can add extra security things in here, for example to limit the fields which you make accessable via the api.
I'm working on a project where I need to be able to mark certain objects for review or deletion. I'm using checkboxes, then using JavaScript to harvest the data from the checkboxes. I'm trying to use AJAX to send that data back to the Rails Controller but I keep getting a 404 error, and I'm not sure what I'm doing wrong.
This is the AJAX call (review_list and purge_list are both defined, I've checked):
function callHandleSelected() {
...
$.post('itemresults/handle_selected', { review: review_list, purge: purge_list },
function(data) {
alert(data);
});
}
And this is the route I wrote to match it:
post 'itemresults/handle_selected', to: 'processed_item#handle_selected'
I've tried adding as: :ajax into the route to see if that makes a difference without any luck.
The HTML element that calls the ajax function looks like so:
<button type="button" class="btn btn-normal" onclick="callHandleSelected()">Mark Selected as Reviewed and/or for Purge</button>
There is also a matching handle_selected method in my Ruby Controller. Every time I try to use the AJAX method I get the following error:
POST http://localhost:3000/itemresults/handle_selected 404 (Not Found) jquery.js?body=1:9667
jQuery.ajaxTransport.send jquery.js?body=1:9667
jQuery.extend.ajax jquery.js?body=1:9212
jQuery.each.jQuery.(anonymous function) jquery.js?body=1:9358
callHandleSelected processed_item.js?body=1:37
onclick
In case you need it, here is the controller method:
def handle_selected
review_list = params[:review]
purge_list = params[:purge]
review_list.each do |item|
item.split("_")
proc_item = ProcessedItem.find(item[1])
proc_item.reviewed = true;
proc_item.save!
end
purge_list.each do |item|
item.split("_")
proc_item = ProcessedItem.find(item[1])
proc_item.purge = true;
proc_item.save!
end
redirect_to processed_items_path()
#add alert
end
I think the problem is just that you need a leading slash on your request url:
$.post('itemresults/handle_selected' ...
should be
$.post('/itemresults/handle_selected'
Without the leading slash, it will add the url onto the end of the current page url.
EDIT: you should put a leading slash on the path in your routes.rb file as well. I think that rails "forgives" you for not doing this but i'm not sure: either way you should do it properly, ie with the leading slash.
A combination of the comments on my initial post answered the question. I took out the redirect_to line and replaced it with this:
respond_to do |format|
format.js {render inline: "location.reload();" }
end
I was getting the 404 error because I was trying to load objects incorrectly as Baloo pointed out. The new (relevant) code looks like this:
review_list.each do |item|
id = item.split("_")[1]
proc_item = ProcessedItem.find(id)
Thanks all!
In rails, this is an api response I'm currently generating as a response from /charts_json/south_carolina.json (for example)
[{"d_s":0,"name":"summerville"},{"d_s":1,"name":"hilton head island"},{"d_s":2,"name":"north myrtle beach"},{"d_s":1,"name":"spartanburg"},{"d_s":12,"name":"greenville, sc"},{"d_s":0,"name":"aiken"},{"d_s":6,"name":"columbia"},{"d_s":4,"name":"myrtle beach"},{"d_s":1,"name":"simpsonville"},{"d_s":1,"name":"lancaster, sc"},{"d_s":0,"name":"north augusta"},{"d_s":0,"name":"sumter"},{"d_s":0,"name":"rock hill"},{"d_s":1,"name":"beaufort, sc"},{"d_s":1,"name":"mount pleasant"},{"d_s":21,"name":"charleston"},{"d_s":1,"name":"clemson"},{"d_s":1,"name":"anderson, sc"}]
Now what I need to do is render the above like this, as a json document
[['0', 'summerville'], ['1', 'hilton head island'], ...etc... ]
For the benefit of the SO community and the clarification of the reader I'll include all the code I'm going to be using to make this work if and when I get this last thing handled
In addition to my charts_controller, I generated a charts_json_controller for responding to json requests--- an example of a controller method in that controller (this is a bit clunky but its ok for now as long as I get functionality)
def south_carolina
#locations = Location.find(1687).descendants #used acts_as_tree gem
respond_to do |format|
format.json { render json: #location.as_json(only: [:d_s, :name])}
end
In the view (cross section)
function drawMarkersMap() {
var data = google.visualization.arrayToDataTable([
['Startups', 'Location'],
$.ajax({url: '/charts_json/south_carolina', dataType: 'json'})
]);
Not sure if I'm understanding correctly, but here's a way to get the json as an array instead of a hash.
define this method for Location
class Location
def self.as_json_array
as_json(only: [:d_s, :name]).collect { |l| [l[:d_s], l[:name]] }
end
end
You could make this more general-purpose if you necessary, but I want to make sure I'm understanding your requirements first.
Then just use that method instead of as_json in your render line.
Also, it sounds like you know this, but you really should just use the same controller and put any custom code for different formats in your respond_to block.
I am trying to access a field in a Ruby on Rails object from my view inside some JavaScript. Here is the relevant code in my view pick.html.erb:
var directionDisplay;
var start = <%= #route.from %>;
var end = <%= #route.to %>;
From and to are text fields that hold zipcodes. Here is my relevant Route controller code:
class RoutesController < ApplicationController
# GET /routes/1/pick
def pick
#routes = Route.find(params[:id])
end
I read somewhere that I need to use ActiveSupport::JSON in order to access an object field...Do I need to do this instead? If so, how do I install it and could you possibly give me an example on how to get started? I've been searching for examples everywhere the past few days and I can't find any.
Let me know if you need any more code and thank you in advance for any reply!
The file name should be (according to convention) pick.js.erb and not pick.html.erb based on the fact that you have JavaScript code included.
If you want to include a partial inside this one, you can use the escape_javascript helper to render the partial.
If you have more than one possible file to be rendered from the pick action, you should look into using respond_to such as:
#route = Route.find(params[:id])
respond_to do |format|
format.html
format.js { render :js => #route }
end