RAILS3: to_JSON with multiple objects and includes - ruby-on-rails

def list
#rings = Ring.order("RAND()")
#JSON RENDERING
render :json => #rings.to_json(:include => [:variations, :stones]), :callback => params[:callback]
end
def show
#showring = Ring.includes(:stones, :variations).find(params[:id])
#other_rings = Ring.select([:id, :stone_count]).where(:style_number => #showring.style_number).reject{ |ring| ring == #showring}
#JSON RENDERING
render :json => {#showring.to_json(:include =>[:variations, :stones]), :other_rings => #other_rings}, :callback => params[:callback]
end
My list view rendering works fine, but when i want to do a show view, with two objects, and showring with includes won't render proper JSON. It is quoting everything in the object with the includes...
JSON output looks like this:
showring => "{"available":"yes","eng...9","stone_y":"149.4"}]}"
other_rings => properly rendered object
On a seperate note, if i have already added the includes to #rings object, why do i then again have to add the association in the "to_json" method?

When you do
render :json => {:show_ring => #showring.to_json(:include =>[:variations, :stones]), :other_rings => #other_rings}
Rails is converting #showring to json (ie getting back a string representation), i.e. the value is the string literal. Instead do
render :json => {:show_ring => #showring.as_json(:include =>[:variations, :stones]), :other_rings => #other_rings}
as_json does all the work of turning the object into a hash but without the final step of turning into a string

if you are going to invest more time in building more JSON objects, you should look into a gem called rabl. It makes building JSON very simple, good for customization which then is good for building API.

Related

TinyMCE Spellcheck expected JSON Response in Rails

I am using TinyMCE and I have rolled my own spellchecker using FFI-Hunspell.
I am just rendering this hardcoded response but when I click the spell check button in the WYSIWYG editor, it says that there aren't any misspelled words.
render :json => {:id => "#{params[:id]}", :result => {"presents" => ["presnts"], "motor" => ["moors"]}}.to_json
So, what is the JSON supposed to look like?
I am using the tinymce_rails gem. I would have thought it was using the newer version. Anyways, I found this link that describes in detail how the request/response should look: https://github.com/spohlenz/tinymce-rails. Effectively, the response for the older version of tinyMCE is this:
render :json => ({:id => nil, :result => ['badk', 'wirds'], :error => nil}).to_json
Also, it actually uses a second request to get the suggestions. And those should look like:
render :json => ({:id => nil, :result => ['bad', 'bed'], :error => nil}).to_json

Rails - Paperclip url in JSON along with other attributes

I've followed Ryan Bates' screencast on using jQuery Tokeninput for an auto-completing list for a many-to-many association. Now I want to pull in a photo for each result. I'm using Paperclip and get the url's passed into a JSON file by doing this in the controller:
format.json { render :json => #users.map(&:photo_url) }
Ryan's code for passing the attributes into a JSON file is this:
format.json { render :json => #users.map(&:attributes) }
But how can I combine the two to display both the :attributes and :photo_url methods in the JSON file?
I've tried different things, including the below code, but nothing seems to work. It seems as if there can only be one method called on .map?
// Doesn't work
format.json { render :json => #users.map(&:attributes, &:photo_url) }
// Doesn't work
format.json { render :json => #users.map(&:attributes).map(&:photo_url) }
Does this help? (Note - I'm just returning from a night out and am not 100%, so I might be misunderstanding your question entirely.)
This creates an array of arrays: The first element in the array contains the user's attributes, and the second contains the photo URL:
#users.map {|u| [u.attributes, u.photo_url]}
This creates a hash - just like the above array. But the first element is named "attributes" and the second is named "photo_url".
#users.map {|u| {:attributes => u.attributes, :photo_url => u.photo_url}}
Try plugging one or both of those in. They should work for you.
(E.g. format.json { render :json => #users.map {|u| [u.attributes, u.photo_url]} }).
Edit:
Just had another thought.
You can merge the two into one collection (so that you'll have it all in one hash instead of separate elements in an array):
#users.map {|u| u.attributes.merge(:photo_url => u.photo_url)}
That'll add photo_url as a key to the attributes hash. It might work more easily for whatever code you've written to read the JSON.
In case of this being helpful to anyone, i find out a nice way to do this:
class MyModel < ActiveRecord::Base
has_attached_file :avatar, :styles => { :large => "500x500#", :medium => "300x300#", :small => "100x100#", :thumb => "50x50#" }
def as_json(options)
json = super
self.avatar.styles.each do | format |
json = json.merge({"avatar_"+format[0].to_s => self.avatar(format[0])})
end
json
end
end
You can then simply call
render :json => #my_model
Also working while rendering collections.
It is then possible to do some conditional rendering with as_json(options), with something like:
model_to_json = #my_model.to_json(:nested => true)
render :json => model_json

Rails render html into a hash

Is it possible to have rails render html into a hash instead of to the client?
Something like this:
#obj = {
"foo" => Bar.find(1)
"html" => (render :partial => "yatzhee")
}
render :json => #obj.to_json
render_to_string takes all the same arguments as render but returns a string. You can then put that in a hash or do anything you want with that.
I never saw anything like that.
If you want to render json, you should really take a look at jbuilder. It's a joy to work with and it's the 'rails way' (~ it's merely built-in).
It allows you to render partials, for instance:
json.partial! "api/comments/comments", #message.comments

How do you output JSON from Ruby on Rails?

I'm looking to have a model that gets created / updated via AJAX. How do you do this in Ruby on Rails?
Also, more specifically: how do you output JSON in RoR?
def create
response = {:success => false}
#source = Source.new(params[:source])
if #source.save
response.success = true
end
render :json => response.to_json
end
All you need to do is call render :json with an object, like so:
render :json => my_object
For most objects, this will just work. If it's an ActiveRecord object, make sure to look at as_json to see how that works. For your case illustrated above, your hash will be transformed to json and returned.
However, you do have an error: you cant access the success key via response.success -- you should instead do response[:success]
jimothy's solution is really good butI believe it isn't scalable in the long term. Rails is meant to be a model, view, and controller framework. Right now JSON is cheated out of a view in default rails. However there's a great project called RABL which allows JSON view. I've written up some arguments for why I think it's a good option and how to get up and running with it quickly. See if this is useful for you: http://blog.dcxn.com/2011/06/22/rails-json-templates-through-rabl/
#source = Source.new(params[:source])
respond_to do | f |
f.html {
# do stuff to populate your html view
# maybe nothing at all because #source is set
}
f.any(:xml, :json) {
render request.format.to_sym => #source
}
end

Filter a model's attributes before outputting as json

I need to output my model as json and everything is going fine. However, some of the attributes need to be 'beautified' by filtering them through some helper methods, such as number_to_human_size. How would I go about doing this?
In other words, say that I have an attribute named bytes and I want to pass it through number_to_human_size and have that result be output to json.
I would also like to 'trim' what gets output as json if that's possible, since I only need some of the attributes. Is this possible? Can someone please give me an example? I would really appreciate it.
Preliminary search results hint at something regarding as_json, but I can't find a tangible example pertaining to my situation. If this is really the solution, I would really appreciate an example.
Research: It seems I can use to_json's options to explicitly state which attributes I want, but I'm still in need of figuring out how to 'beautify' or 'filter' certain attributes by passing them through a helper before they're output as json.
Would I create a partial for a single json model, so _model.json.erb, and then create another one for the action I'm using, and within that simply render the partial with the collection of objects? Seems like a bunch of hoops to jump through. I'm wondering if there's a more direct/raw way of altering the json representation of a model.
Your model can override the as_json method, which Rails uses when rendering json:
# class.rb
include ActionView::Helpers::NumberHelper
class Item < ActiveRecord::Base
def as_json(options={})
{ :state => state, # just use the attribute when no helper is needed
:downloaded => number_to_human_size(downloaded)
}
end
end
Now you can call render :json in the controller:
#items = Item.all
# ... etc ...
format.json { render :json => #items }
Rails will call Item.as_json for each member of #items and return a JSON-encoded array.
I figured out a solution to this problem, but I don't know if it's the best. I would appreciate insight.
#items = Item.all
#response = []
#items.each do |item|
#response << {
:state => item.state,
:lock_status => item.lock_status,
:downloaded => ActionController::Base.helpers.number_to_human_size(item.downloaded),
:uploaded => ActionController::Base.helpers.number_to_human_size(item.uploaded),
:percent_complete => item.percent_complete,
:down_rate => ActionController::Base.helpers.number_to_human_size(item.down_rate),
:up_rate => ActionController::Base.helpers.number_to_human_size(item.up_rate),
:eta => item.eta
}
end
respond_to do |format|
format.json { render :json => #response }
end
Basically I construct a hash on the fly with the values I want and then render that instead. It's working, but like I said, I'm not sure if it's the best way.

Resources