views:

325

answers:

4
[
   {
      "id":"123",
      "name":"House"
   },
   {
      "id":"1456",
      "name":"Desperate Housewives"
   },
   {
      "id":"789",
      "name":"Dollhouse"
   },
   {
      "id":"10",
      "name":"Full House"
   }
]

How can I render to produce this JSON format from within Ruby? I have all the data from the DB (@result) and don't know what data structure to use in Ruby that will render to this when I do this:

respond_to do |format|    
    format.json { render :json => @result}
end

What data structure should @result be and how can I iterate to produce it? Thank you!

A: 

Try using the json gem. It will allow to you do things like

@result.to_json

to convert your structures (say, a Hash) to json format. If you're using Ruby on Rails, this functionality should already be accessible to you, so just create a Hash and call to_json.

Evgeny Shadchnev
+3  A: 

If @result is an array of ActiveRecord model instances then render :json => @result will produce something like what you are after, but will include all the attributes of the model (render calls to_json on the object you pass it unless it is a string).

To only include the id and name attributes, you can use the :only parameter of to_json:

respond_to do |format|    
  format.json { render :json => @result.to_json(:only => [:id, :name] }
end

Alternatively, you can create a array of Hash objects that only contain the required attributes:

respond_to do |format|    
  format.json { render :json => 
                  @result.collect {|o| {:id => o.id, :name => o.name} } }
end

Edit: See @dt's comment below. There is an attribute in the model named text that needs to be output as name. This can be done by creating an alias for text in the model:

class Model < ActiveRecord::Base
  alias_method :name, :text

and including the name using :methods:

respond_to do |format|    
  format.json { render :json => @result.to_json(:only => :id, :methods => :name }
end

Alternatively, the array of hashes approach can be used to rename the attribute:

respond_to do |format|    
  format.json { render :json => 
                  @result.collect {|o| {:id => o.id, :name => o.text} } }
end
Phil Ross
thank you, that is almost it, but the issue is that the results I get from ActiveRecord do not have the :name attribute, so essentially I need to loop through it and reassign my attribute (text) to name, so I think I need maybe to create a hash inside the for/do loop and then add it to an array?@simianarmy suggests something close, but i don't know how to iterate to create that. does the order matter? when I print it out it always puts name before id. will that matter?@evgeny I have the gem installed, thank you!thank you. each answer is helpful!
dt
Whether or not 'id' comes before 'name' does not matter.
rspeicher
@dt There are two options: 1) Add a method called `name` to your model and then call `@result.to_json(:only => :id, :methods => :name)`. 2) Modify the `collect` statement to rename the attribute: `@result.collect {|o| {:id => o.id, :name => o.text}}. The order of the attributes in the output will be dependent on how Hash orders the keys, but shouldn't be important to anything parsing the JSON output.
Phil Ross
Phil, thanks! That worked!!
dt
+1  A: 

To create a JSON object of that particular format, you need a ruby array containing hashes for its elements.

@result = [{:id => "10", :name => "Full House"}, {:id => "789", :name => "blahblah"},...]

Rails will convert the ruby array to json correctly in your render response block:

respond_to do |format|    
  format.json { render :json => @result}
end
simianarmy
resultsarray = [] for r in @result resultshash = {:id => r.id, :name => r.text} resultsarray<<resultshash endeach time i do this, it puts the name first, so that the json returned is in the wrong order. will that matter? it's not working, so i think that could be it?
dt
A: 

I was using a jQuery plugin (FCBKComplete) that needed the json results with specific key names, specifically 'caption' and 'value', which did not exist in the array I was calling to_json on.

So I did this (hacky, but it works):

render :json => taggings.map { |t| {:caption => t.tag.name, :value => t.tag.name} }.to_json

Where taggings is an array returned by an ActiveRecord find, and that returns json like so:

[{"value":"tag.a","caption":"tag.a"},{"value":"tag.b","caption":"tag.b"}]
rspeicher