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
Related
I'm trying to get some virtual (non-persisted) attributes to show up in the JSON representation of some Mongoid models, but can't seem to get it to work:
class MyModel
include Mongoid::Document
def virtual_attribute
#my_attribute || false
end
def virtual_attribute=(value)
#my_attribute=value
end
end
class MyController
def myaction
false_values=MyModel.where( whatever )
true_values=MyModel.where( something_else ).map{ |model| model.virtual_attribute=true }
#val['my_models']=false_values+true_values
render json: #val.to_json( :include => {:my_models => {:methods => %w(virtual_attribute)}} )
end
end
virtual_attribute doesn't appear in the json. What am I doing wrong?
Edit - ok, so I guess my actual problem is that I can't figure out how to invoke the virtual_attribute method on each of an array of objects that is nested in the root object.
to_json passes the options directly to the array and the objects. :include is only a Mongoid thing:
render json: #val.to_json(methods: :virtual_attribute)
I want a way to set an ActiveRecord model to output only the fields I am letting it regardless of where it is accessed. I dont want to do this wherever an object of the model is accessed:
#jobs = Job.all
#jobs = #jobs.to_json(
:include => {:job_status},
:except => [:created_at, :updated_at]
)
I want to set this so that wherever the Job models object is rendered it will automatically include and exclude those fields/associations.
You can override as_json on the Job class.
def as_json(options=nil)
super(:include => {:job_status},
:except => [:created_at, :updated_at])
end
I have a post model that has a virtual attribute that I would like to set and then include in a response to a JSON call to my post#index action. I can't seem to get the virtual attribute to be included in the response.
class Post < ActiveRecord::Base
attr_accessible :height
attr_accessor :m_height
end
class PostsController < ApplicationController
respond_to :html, :json, :js
def index
story = Story.find(params[:story_id])
#posts = story.posts.where("posts.id >= ?", 100)
#posts.each do |post|
post.m_width = post.height * 200
end
results = { :total_views => story.total_views,
:new_posts => #posts }
respond_with(results)
end
end
I think that I must need something similar to #post.to_json(:methods => %w(m_width)), but I don't see how to use :methods in a respond_with
This seems to provide the answer. Implement a to_json and to_xml in your models, as appropriate, with definitions like:
There's a better answer implied here.
Following code stolen from the post:
def as_json(options={})
super(options.merge(:methods => [...], :only => [...], :include => [...])
end
to_json won't be called on your model in this case, from what I can tell in the source, but as_json will be, in the process of serialization.
So, here's what happens, in overview form:
You call respond_with with the results hash you've constructed.
Rails (ActionController) calls to_json on that.
to_json sends you over to JSON::Encoding which keeps calling as_json all the way down until everything is JSONified.
That's why there was the confusion about to_json and as_json in an earlier version of this answer.
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
I am using ActiveRecord's as_json integration with ActiveSupport::JSON to render custom output in my controllers. A basic setup I have in my model looks something like this:
def as_json(options = {})
{ :guid => id,
:title => title,
:body => body,
:date => created_at }
end
I want to take this setup a step further and show select information depending upon options passed. My question is, when I call respond_with #model_instance or render :json => #model_instance am I able to pass options that the options argument in as_json receives? If not, should I just create and convert a unique hash in my controller?
Seems like you could just call .as_json and pass in the options, no?
render :json => #mymodel.as_json(:someoption =>" value")