How do I display a d3.js circle pack graph with RoR? - ruby-on-rails

I am trying to set up a graph like this http://bl.ocks.org/4063269#index.html with d3.js:
I need to do this by putting methods in a controller and the js in a .html.haml file. I have made the controllers, but have absolutely no idea how to write the methods.
The methods need to take values from a sqlite3 database and convert it into JSON for the d3.js to use. Could someone get me started? I have no idea what to do right now...

Unfortunately the question you are making is too open, with more details you will get more help ;)
So the javascript library is going to make ajax call to your application, and your application should respond with json?
In that case, you can just do the routing on config/routes.rb, and then you just write a method like this:
class MyController < ApplicationController
def values_for_js
my_data = MyModel.calculate_data
respond_to do |format|
format.json { render json: my_data.to_json }
end
end
end
And your js should request something like http://mywebsite.com/values_for_js.json (or it can say in the ajax request that a json format is expected). If you are not able to make the json request, you can just use format.js instead of format.json

Related

Using Rails as a "Half-API"?

Im not sure if what I want to do is possible or even makes sense, basically I want to use a rails application that server a API and has a web component as well.
My plan is to have some sensors send POST data (from some Raspberry Pi Zero's) to this rails backend. I want to also be able to GET sensor data in JSON form from the backend api via some sort of nice URL (GET sensor_id/temp or something).
However I also want to be able to have a sort of dashboard that displays values over X timeline for instance.
At that point, does it really make sense using the new rails 5 API addition (--api when making a new rails project) or should I actually separate it into 2 separate backends? (Feeding one into the other)
Yes this is possible. You would define your controller action like this:
def index
#people = Person.find(:all)
respond_to do |format|
format.html do
#do some html specific stuff here
end
format.json { render :json => #people.to_json }
end
end

Create a generic template for JSON from a rails application

I'm writing a rails application with an AngularJS front-end, this is part of a tutorial series I'm writing on connecting rails and angularjs. This means my rails application communicates with the browser exclusively in JSON.
In the angularjs $http documentation it describes a potential json security vulnerability where the json request can be embedded into a script tag, plus some tricky use of jsonp, to allow something akin to a cross-site scripting attack. I've found a few other pages, one in particular I thought described this well, and dates from 2008, so this isn't a new issue.
Apparently this isn't a vulnerability in standard rails json rendering, as rails by default provides back an object containing an array. But when working with angularjs we appear to set root: false (although I have to confess I can't find where I did that, but it's definitely not giving the root node).
Anyway, the bottom line is that the angular documentation recommends prefixing any json response with )]}', so:
['one','two']
Becomes
)]}',
['one','two']
Angular then automatically strips that off again.
I'm looking for a way to do this elegantly. I've seen a lot of questions and answers on stackoverflow about this, but most of those either relate to much earlier versions of rails before JSON handling was more thoroughly embedded, or seem to require me to create a lot of boilerplate code. I'm looking for a method that I can apply to the application controller, or as a helper method, that will work everywhere.
The controller that I'm currently using looks as follows:
class ClubsController < ApplicationController
respond_to :json
# GET /clubs.json
def index
#clubs = Club.all
render json: #clubs
end
end
This doesn't call any templates - the render action skips the templating engine. I can get this working by changing the render line instead to:
respond_with json: #clubs
And creating a template file views/clubs/index.json.erb that contains
)]}',
<%= raw(#clubs.to_json) %>
But I'd then have to create a template for every action on every controller, which feels like boilerplate. I'd like instead to be able to change views/layouts/application.json.erb to have something like:
)]}',
<%= yield %>
But that doesn't work because we only get templating if we call respond_with. And if we call respond_with, we have no way to put the #clubs into the response - so we end up with:
)]}',
As the entirety of the response.
An alternative would perhaps be to override the as_json method to prepend what I want, but that seems a bit like a sledgehammer. Ideally there would be a place I could introduce a helper method, something like:
render prepend_vulnerability_protection(json: #clubs)
So, after all that, two questions:
Is this even a real problem, or does Rails already have some other protection that means I don't need to worry about this at all
Is there a way to do this centrally, or do I need to bite the bullet and create all the boilerplate templates? I can modify the scaffold generators to do it, so it's not the end of the world, but it does seem like a lot of boilerplate code
So, no responses as yet. I'm going to write down what I find from my research, and my current answer.
Firstly, I think this is a genuine vulnerability in rails. Unfortunately the rails and JSON/JSONP area has had some other recent vulnerabilities relating to the JSON parser at the Rails end. That has really drowned out any google search relating to this specific XSS issue.
There are a couple of approaches to resolving this:
Have your application only respond to put/post/delete requests. That's not really an option when integrating to Angular - well, it is, but it means overriding a bunch of standard behaviour
Insert something at the front of your returned JSON - this can be the root node (default rails behaviour in rails 3, no longer in 3.1), a closure like )]};, or a loop like while (1);. Angular expects and can deal with )]}',
I've looked at using a json template in my rails app. You can do this with one of many gems, the one I like the look of is JBuilder (railscast 320), but RABL is perhaps more powerful (railscast 322).
This does mean a template for each of the actions on each of the controllers. However, I've also just completed working out how to have rails scaffold those for me automatically, so it's not as scary as it was when I first asked the question, and I can see some other reasons that I might want more control over the json that is returned from my application.
Having said that, I couldn't immediately see a way to get JBuilder to prepend an arbitrary string - it seems to only want to prepare valid JSON (and this I think is not valid JSON). RABL looks like it can do it, but it is a bit more complex. It can definitely be done through just using ERB, but I feel kinda wrong in doing that.
The other alternative I've identified is a helper method in application_controller.rb, which I then call in each of my controller methods. This is reasonably elegant, and I can quite easily change my template to do it. So I'm going with this for now:
class ApplicationController < ActionController::Base
def render_with_protection(json_content, parameters = {})
render parameters.merge(content_type: 'application/json', text: ")]}',\n" + json_content)
end
end
class ClubsController < ApplicationController
respond_to :json
# GET /clubs.json
def index
#clubs = Club.all
render_with_protection #clubs.to_json
end
# GET /clubs/1.json
def show
#club = Club.find(params[:id])
render_with_protection #club.to_json
end
# POST /clubs.json
def create
#club = Club.new(params[:club])
if #club.save
render_with_protection #club.to_json, {status: :created, location: #club}
else
render_with_protection #club.errors.to_json, {status: :unprocessable_entity}
end
end
end
Note that you should be also including CSRF protection in your application controller - so see this as additive to the security precautions you were already taking, not a replacement.

Why do controllers need multiple format renderings?

Please explain why do we need this code in a controller? What is the significance of this block of code?
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
It allows you to format output differently depending on the format the user/caller requests. If you were to access http://yourhost/controller/index.html, the controller would respond with the ERB template index.html.erb (or HAML or whatever). If you were to access http://yourhost/controller/index.json, it would respond with the JSON template index.json.erb.
This allows you to have a single controller action that can prepare data and then select the view for rendering based on the requested format.
Defines mime types that are rendered by default when invoking respond_with.
So basically, this means that your controller action can be hit in different formats(html, json in your case), and still provide data back to whatever is calling it. This is helpful for API development, and many other things.
For example: You want to get a json list of all your users to do something with javascript. You'd call /users.json and this would go to your user_controller#index action and know to render a json object of all your users.
The above code is scaffold generated, and provides a way to render *.html and *.json views for your controller, making it easy to have access to data for implementing an API or normal views for your web application.
You can also create XML output:
format.xml { render xml: #users }
and other formats like PDF, or DOC, depending on the gems you are using.
See the Rails Guide Action Controller Overview for more information.

Rails 3: HTTP 406 and blank page on trying to view json in browser

I am a little new with Rails and ajax, and I'm encountering the following frustration whilst trying to debug some fairly simple ajax requests in my controllers.
I have the following code:
respond_to do |format|
#format.html { render :json => db_clean_response.to_json }
format.json { render :json => db_clean_response.to_json }
end
When I try to debug this by manually entering the URL and parameters, the controller correctly prepares the response, but Rails responds with HTTP/406 Not Acceptable unless I uncomment the format.html command. (Note that the format.html stuff is just for trying to fix this.)
I don't want this function responding with html, as its only for ajax stuff. Besides, Rails responds with the json uglyprinted onto empty html, and I'd like to use a plugin like JSONView to prettify it.
What's going on here? I feel like the desired result is very simple, but something, somewhere is messing it up. When I try to debug ajax I want my browser to pull up the damn json without being lame :-(
It turns out that adding format=json to the URL parameters does what I want: forces Rails to return json with all the right headers

How to modify the default RoR behavior to AJAX CRUD?

I want a table to do CRUD, but I want it in an Ajax way, how can I modify the default RoR behavior, any suggestions on that?
I tried comment these code in destroy method, but it don't work, it saw missing the destroy.erb:
respond_to do |format|
format.html { redirect_to(categories_url) }
format.xml { head :ok }
end
It will default to HTML if you don't give (and accept) a different response. Check out this railscast to see how to set up an AJAX request and response with RJS (there's another on how to do it with jQuery).
Basically you'll need a format.js line. You can also make a view of the form .js.erb where you write JavaScript to run on the server response.
As a side note though, unless you have a very specific website, I'd suggest not doing only AJAX. It's not very accessible for users without JavaScript, like blind users with a screenreader.

Resources