Ruby data structure to render a certain JSON format - ruby-on-rails

[
{
"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!

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

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.

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

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"}]

Related

Adding strings to Rails JSON output

I need to output custom JSON in order to be backwards compatible with existing software, which is written in Javascript, so I need to wrap my JSON with "parseDate(" at the beginning of it, and ");" at the end of it.
I tried doing it in controller like this
def index
#data = Data.all
#products = Product.all
respond_to do |format|
format.html
format.json {render :json => { :products => {:product => #data.name}}}
end
end
And then specify it in the view:
app/views/products.json.erb
<%= p "parseData(" %>
<%= render :json %>
<%= p "};" %>
But it outputs pure JSON completely skipping both "parseData(" and ");", why? How do I make JSON to be printed in the middle of the view and then append strings to the top and bottom?
JSON renderer supports a callback option.
format.json { render :json => { :products => {:product => #data.name }}, :callback => 'parseDate' }
You can read the implementation in the renderer.rb source code.

how can i get the values using include with conditions in rails?

I have the shop with has_many association and include items to it so that the items belonging to that shop is received
format.json { render json: {:shop => #shops.as_json(:include => :items)}}
now it gives all the items that belongs to that shop but i want to get items with specific condition, say item_type = "accessories". so how can i do this? please help me.
EDIT
I have put a new question in How to get the value of include with conditions?
You should filter the data with ActiveRecord, and then call the as_json on the filtered data.
You can do something like:
#shops = Shop.includes(:items).where("items.itemp_type = ?", 'accesories')
format.json { render json: { :shop => #shops.as_json(:include => :items) } }
One way you could do this is to create a hash with the objects you want to render, and then pass that to the render method. Like so:
respond_to do |format|
format.json { render :json => {:shops => #shops,
:items => #items }}
end
If the models aren't associated through active record, that's probably your best solution.
If an association does exist, you can pass an :include argument to the render call, like so:
respond_to do |format|
format.json { render :json => #shops.to_json(:include => [:items])}
end
Note that you wouldn't have to retrieve the #items variable in the section above if you take this approach, Rails will automatically load it from the #shops variable.

How to get the value of include with conditions?

I have three table say shop, item and item_type
the shop contains names of shops and item contains items of each shop and item_type contains different types of that items along with the status such as available or not available.
Now i want to render
format.json { render json: {:shop => #shops.as_json(:include => :items)}}
but based on the condition, say items with the item_type_id='1' and status of the item_type_status='available'
Try this:
#shops = Shop.includes(:items).where("items.itemp_type = ?", 'accesories')
format.json { render json: { :shop => #shops.as_json(:include => :items) } }
Edited:
One way you could do this is to create a hash with the objects you want to render, and then pass that to the render method. Like so:
respond_to do |format|
format.json { render :json => {:shops => #shops,
:items => #items }}
end
If the models aren't associated through active record, that's probably your best solution.
If an association does exist, you can pass an :include argument to the render call, like so:
respond_to do |format|
format.json { render :json => #shops.to_json(:include => [:items])}
end
Note that you wouldn't have to retrieve the #items variable in the section above if you take this approach, Rails will automatically load it from the #shops variable.
You can pass method or methods to to_json or as_json methods and include needed records. Example from Rails api:
user.as_json(:methods => :permalink)
# => {"id": 1, "name": "Konata Izumi", "age": 16,
"created_at": "2006/08/01", "awesome": true,
"permalink": "1-konata-izumi"}

Rails Include filtered model in Json object

I have the following controller code
respond_with(#employees) do |format|
format.json { render :json => #employees.to_json(:include => :shifts) }
end
What do i have to do if i want to filter the shifts which are included? For example by a date.
I have to be able to set the filter parameters in the controller.
Edit:
I thought about using :method but it creates another variable in the json object. It has to be called "shifts"
format.json { render :json => #employees.includes(:shifts).where("shifts.date > ?", your_date_here).to_json(:include => :shifts) }

render :json does not accept options

I'd love to use render :json but it seems its not as flexible. Whats the right way to do this?
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #things }
#This is great
format.json { render :text => #things.to_json(:include => :photos) }
#This doesn't include photos
format.json { render :json => #things, :include => :photos }
end
I've done something similar with render :json. This is what worked for me:
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #things.to_json(:include => { :photos => { :only => [:id, :url] } }) }
end
I guess this article can be useful for you - Rails to_json or as_json? by Jonathan Julian.
The main thought is that you should avoid using to_json in controllers. It is much more flexible to define as_json method in your model.
For instance:
In your Thing model
def as_json(options={})
super(:include => :photos)
end
And then you can write in your controller just
render :json => #things
Managing complex hashes in your controllers gets ugly fast.
With Rails 3, you can use ActiveModel::Serializer. See http://api.rubyonrails.org/classes/ActiveModel/Serialization.html
If you're doing anything non-trivial, see
https://github.com/rails-api/active_model_serializers. I recommend creating separate serializer classes to avoid cluttering your models and make tests easier.
class ThingSerializer < ActiveModel::Serializer
has_many :photos
attributes :name, :whatever
end
# ThingsController
def index
render :json => #things
end
# test it out
thing = Thing.new :name => "bob"
ThingSerializer.new(thing, nil).to_json
format.json { render #things.to_json(:include => :photos) }
in case of array what I done is
respond_to do |format|
format.html
format.json {render :json => {:medias => #medias.to_json, :total => 13000, :time => 0.0001 }}
end

Resources