Include nested json in Rails - ruby-on-rails

I added an object nested in another object using the model. Just like this:
Ingresso model ->
def as_json(options=nil)
super(:include => [:usuario, :tipo_de_ingresso])
end
In tipo_de_ingresso model, I want to add another object nested. here:
def as_json(options=nil)
super(:include => :entradas)
end
But when I get the the ingressos.json, I lost entradas. If I get tipo_de_ingressos.json, entradas are nested, ok, but when I get ingressos.json, they are not there.
How can I get entradas nested in tipo_de_ingresso when I call ingresso?

Try this,
# /app/models/Ingresso.rb
def as_json(options=nil)
super(:include => [:usuario => {}, :tipo_de_ingresso => { :include => :entradas }])
end
EDIT:
changed [:usuario, ... to [:usuario => {}, ...

Related

Rails - Include association in json response

I got 2 Tables/Models: Paths and Questions. Each question belongs to a path
My question.rb:
class Question < ActiveRecord::Base
belongs_to :path
end
My path.rb
class Path < ActiveRecord::Base
has_many :questions
end
Everything works fine like
p = Path.last
Path.questions
returns everything I need but I'm returning a json response like this:
#path = Path.find_by_id(params[:id])
render :status=>200, :json => {:status => "success", :path => #path, :message => "Showing path"}
That answer doesn't include the questions for the path of course. What do I have to change to include all questions belonging to that path? I know I could just add :path_questions => #path.questions but is there no way to include the questions without a new return variable? I hope it's clear what I mean.
I do it like that in a Rails 5 API app:
BooksController
def index
#books = Book.limit(params[:limit])
render json: #books, include: ['author'], meta: { total: Book.count }
end
In the above situation, a Book belongs_to Author.
This is quite hacky, but should work:
:path => #path.as_json.merge(:questions => #path.questions.as_json)
Eventually you can override as_json inside your model:
def as_json(options={})
includes = [*options.delete(:include)]
hash = super(options)
includes.each do |association|
hash[self.class.name.underscore][association.to_s] = self.send(association).as_json
end
hash
end
And then just call: :path => #path.as_json(:include => :questions)
Note it will also add :include option to to_json method.

Shortening up respond_with( :include => xxx)

I'm looking for a way to shorten up the :include => :child inside a respond_with which generates json.
Here is an example, not sure if it is even possible, but I would like to find out.
In the controller:
#p = Parent.where('id = ?', params[:id])
respond_with(#p, :include => {:child1 => {}, :child2 => {}, :child3 => {:include => :grandchild1}})
Is there someway to include these all when I define the instance?
Maybe something like:
#p = Parent.includes(:child1, :child2, :child3, :grandchild1).where('id = ?', params[:id])
respond_with(#p)
Basically, I'm trying to DRY up my code ... I don't want to have to keep typing the include hash over and over ... Is there someway to just include all child objects in one call?
ActiveRecord has an as_json method that defines how the object should be outputted as json. You can ovveride this method to include the associated children by default so something like this:
class Parent < ActiveRecord::Base
# We went to display grandchildren by default in the output JSON
def as_json(options={})
super(options.merge(:include => {:child1 => {}, :child2 => {}, :child3 => {:include => :grandchild1}})
end
end
That should let you clean up your controller a bit, you only need this:
#parent = Parent.find(params[:id])
respond_with #parent

problem using 'as_json' in my model and 'render :json' => in my controller (rails)

I am trying to create a unique json data structure, and I have run into a problem that I can't seem to figure out.
In my controller, I am doing:
favorite_ids = Favorites.all.map(&:photo_id)
data = { :albums => PhotoAlbum.all.to_json,
:photos => Photo.all.to_json(:favorite => lambda {|photo| favorite_ids.include?(photo.id)}) }
render :json => data
and in my model:
def as_json(options = {})
{ :name => self.name,
:favorite => options[:favorite].is_a?(Proc) ? options[:favorite].call(self) : options[:favorite] }
end
The problem is, rails encodes the values of 'photos' & 'albums' (in my data hash) as JSON twice, and this breaks everything... The only way I could get this to work is if I call 'as_json' instead of 'to_json':
data = { :albums => PhotoAlbum.all.as_json,
:photos => Photo.all.as_json(:favorite => lambda {|photo| favorite_ids.include?(photo.id)}) }
However, when I do this, my :favorite => lambda option no longer makes it into the model's as_json method.......... So, I either need a way to tell 'render :json' not to encode the values of the hash so I can use 'to_json' on the values myself, or I need a way to get the parameters passed into 'as_json' to actually show up there.......
I hope someone here can help... Thanks!
Ok I gave up... I solved this problem by adding my own array methods to handle performing the operations on collections.
class Array
def to_json_objects(*args)
self.map do |item|
item.respond_to?(:to_json_object) ? item.to_json_object(*args) : item
end
end
end
class Asset < ActiveRecord::Base
def to_json_object(options = {})
{:id => self.id,
:name => self.name,
:is_favorite => options[:favorite].is_a?(Proc) ? options[:favorite].call(self) : !!options[:favorite] }
end
end
class AssetsController < ApplicationController
def index
#favorite_ids = current_user.favorites.map(&:asset_id)
render :json => {:videos => Videos.all.to_json_objects(:favorite => lambda {|v| #favorite_ids.include?(v.id)}),
:photos => Photo.all.to_json_objects(:favorite => lambda {|p| #favorite_ids.include?(p.id)}) }
end
end
I think running this line of code
render :json => {:key => "value"}
is equal to
render :text => {:key => "value"}.to_json
In other words, don't use both to_json and :json.

Rails: How can I render multiple objects to JSON?

I am trying to render multiple objects as JSON. This is my render call:
render :json => {:widget => #widget.to_json(:include => :foo),
:updated => Time.now.to_i}
I have to use to_json because of the include, and the addition updated so I know when the last call was made. The problem is that the to_json is rendered as a String instead of the object structure of the widget.
How do I get the full object structure of the widget and the updated information?
Move the :include => :foo into your Widget model.
class Widget < ActiveRecord::Base
def as_json(options = {})
super options.merge(:include => :foo)
end
end

Including nested objects in JSON response, from MongoMapper objects

class Api::StoresController < ApplicationController
respond_to :json
def index
#stores = Store.all(:include => :products)
respond_with #stores
end
end
Returns only stores without their products, as does
Store.find(:all).to_json(:include => :products)
The association is tested, I can see the nested products in console ouput from, say,
Store.first.products
What's the correct way to get them products included with MongoMapper?
Here are my models:
class Store
include MongoMapper::Document
many :products, :foreign_key => :store_ids
end
class Product
include MongoMapper::Document
key :store_ids, Array, :typecast => 'ObjectId'
many :stores, :in => :store_ids
end
UPDATE
In trying Scott's suggestion, I've added the following to the Store model:
def self.all_including_nested
stores = []
Store.all.each do |store|
stores << store.to_hash
end
end
def to_hash
keys = self.key_names
hash = {}
keys.each{|k| hash[k] = self[k]}
hash[:products] = self.products
hash[:services] = self.services
hash
end
And in the controller:
def index
#stores = Store.all_including_nested
respond_with #stores
end
Which looks like it should work? Assuming the array of hashes would have #to_json called on it, and then the same would happen to each hash and each Product + Service. I'm reading through ActiveSupport::JSON's source, and so far that's what I've grokked from it.
But, not working yet... :(
Have a look at the as_json() method. You put this in your models, define your json, and then simply call the render :json method and get what you want.
class Something
def as_json(options={})
{:account_name => self.account_name,
:expires_on => self.expires_on.to_s,
:collections => self.collections,
:type => "Institution"}
end
end
You'll notice self.collections which is a many relationship. That model also has as_json() defined:
class Collection
def as_json(options={})
{:name => self.name,
:title => self.title,
:isbn => self.isbn,
:publisher => self.publisher,
:monthly_views => self.monthly_views}
end
end
This one contains self.monthly_views which represents another many relationship.
Then in your controller:
#somethings = Something.all
render :json => #somethings
You might have to create your own method to generate a hash then turn the hash into JSON. I'm thinking something like this:
store = Store.first
keys = store.key_names
hash = {}
keys.each{|k| hash[k] = store[k]}
hash[:products] = store.products
hash.to_json

Resources