First of all, I'm using Rails 3.0.6 and Ruby 1.9.2
I have a controller with two different actions, both should return a json object, but with different formats. Therefore I'm overriding the as_json method to write the JSON object in my own format. Problem is that I don't know how to pass params to as_json method since it's being automatically called by Rails.
My code looks like this:
class MyController < ApplicationController
def action1
# my code
respond_to do |format|
# Render with :json option automatically calls to_json and this calls as_json
format.js { render :json => #myobjects }
end
end
def action2
# a different code
respond_to do |format|
# This action should return a JSON object but using a different format
format.js { render :json => #myobjects }
end
end
end
class MyModel < ActiveRecord::Base
def as_json(options = {})
# I would like to add a conditional statement here
# to write a different array depending on one param from the controller
{
:id => self.id,
:title => self.description,
:description => self.description || "",
:start => start_date1.rfc822,
:end => (start_date1 && start_date1.rfc822) || "",
:allDay => true,
:recurring => false
}
end
end
Note that #myobjects are a collection of objects which class is MyModel.
Any help would be appreciated. Thank you!
Call it explicitly in controller and pass params. as_json will return string and calling as_json on string returns itself. It is quite common practice.
respond_to do |format|
# Render with :json option automatically calls to_json and this calls as_json
format.js { render :json => #myobjects.as_json(params) }
end
Related
I have an action as :
def get_data
#people = Person.all
respond_to do |format|
format.json do
render :json => {
:success => true,
:people => #people.as_json({
:only => [:person_name, :text_description, :text_heading],
:methods => [:title,:age_group],
})
}
end
end
end
Here title and age_group are my methods in model Person
def age_group
self.name
end
Now i want to method to look like this
def age_group(age)
# ...
end
How do i pass this argument from the controller as the methods representation there is as symbol.
Hi as per my suggestion you can override method or create a instance method depending upon options it will generate hash or json.If you want to use as_json then you can dig into code this line is helpful for digging code https://github.com/rails/rails/blob/2-3-stable/activerecord/lib/active_record/serialization.rb#L33 which will give you how methods being passed.
I currently have this method in a controller:
def show
property = Property.find(params[:id])
respond_to do |format|
format.xml { render :xml => property.to_xml(:except => [:address1, :address2, :analysis_date, :analysis_date_2, ...]) }
format.json { render :json => property.to_json(:except => [:address1, :address2, :analysis_date, :analysis_date_2, ...]) }
end
end
It seems like I can refactor this code to use respond_with, but I am not sure how to customize the output. Do I need to override the as_json and to_xml methods in order to customize the returned data? If I override these methods, will property associations still be handled correctly? For example, a property has many tenants and many contractors. I may need to return those elements as well.
I would assume the controller method could then be simplified to this.
def show
property = Property.find(params[:id])
respond_with(property)
end
The respond_with method takes two arguments: the resources*and a &block so you should be able to do this:
def show
property = Property.find(params[:id])
respond_with(property, :except => [:address1,
:address2,
:analysis_date,
:analysis_date_2,
...])
end
And just remember, that in order to us respond_with properly you need to add respond_to :html, :json, :xml in the top of your controller. So that respond_withknows what mimes to respond to.
AlbumsController:
respond_to :json
def index
respond_with albums.ordered
end
Now how can I make it so that the underlying call to_json always executes with this options: except => [:created_at, :updated_at]? And I don't mean just for this action, but for all others actions defined in this controller.
The as_json method is what is used to serialize into json
class Album
def as_json(params={})
params.merge! {:except=>[:created_at, :updated_at]}
super(params)
end
end
You could define serializable_hash on your model which defines the keys and values to return. Rails will then return JSON / XML based on this hash:
def serializable_hash
{ :name => "Stack Overflow",
:created_at => created_at",
:posts_count => posts.count
}
end
I'm trying to pass an object (the current user) to be used when rendering the json for a collection.
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #items }
format.json { render :json => #items.to_a.as_json(:user => current_user) }
end
However, this seems to have no effect as options[:user] is nil in the as_json method.
JSON_ATTRS = ['id', 'created_at', 'title', 'content']
def as_json(options={})
# options[:user] is nil!
attributes.slice(*JSON_ATTRS).merge(:viewed => viewed_by?(options[:user]))
end
Anyone know why this doesn't work, or can suggest a more elegant way to have the json renderer be aware of the current user?
Thanks,
Wei
you are calling as_json on an Array (#items.to_a), are you sure that is what you want?
If you are trying to call it on your models then you need to do something like #items.to_a.map{|i| i.to_json(:user => current_user)} (and you probably don't need the to_a).
And it is to_json you should be calling. It will invoke as_json to get your properties, passing along whatever options you provide it with, but return a properly formated json-string (as_json returns a ruby object).
BTW, if you want to pass the options on down to "child" associations, I found that this worked (at least on a mongo_mapper backed project):
def as_json(options={})
{
:field1 => self.field1,
:field2 => self.field2,
:details => self.details.map{|d| d.to_json(options)}
}
end
I have an ActiveRecord model that I would like to convert to xml, but I do not want all the properties rendered in xml. Is there a parameter I can pass into the render method to keep a property from being rendered in xml?
Below is an example of what I am talking about.
def show
#person = Person.find(params[:id])
respond_to do |format|
format.xml { render :xml => #person }
end
end
produces the following xml
<person>
<name>Paul</name>
<age>25</age>
<phone>555.555.5555</phone>
</person>
However, I do not want the phone property to be shown. Is there some parameter in the render method that excludes properties from being rendered in xml? Kind of like the following example
def show
#person = Person.find(params[:id])
respond_to do |format|
format.xml { render :xml => #person, :exclude_attribute => :phone }
end
end
which would render the following xml
<person>
<name>Paul</name>
<age>25</age>
</person>
You can pass an array of model attribute names to the :only and :except options, so for your example it would be:
def show
#person = Person.find(params[:id])
respond_to do |format|
format.xml { render :text => #person.to_xml, :except => [:phone] }
end
end
to_xml documentation
I just was wondering this same thing, I made the change at the model level so I wouldn't have to do it in the controller, just another option if you are interested.
model
class Person < ActiveRecord::Base
def to_xml
super(:except => [:phone])
end
def to_json
super(:except => [:phone])
end
end
controller
class PeopleController < ApplicationController
# GET /people
# GET /people.xml
def index
#people = Person.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #people }
format.json { render :json => #people }
end
end
end
I set one of them up for json and xml on every object, kinda convenient when I want to filter things out of every alternative formatted response. The cool thing about this method is that even when you get a collection back, it will call this method and return the filtered results.
The "render :xml" did not work, but the to_xml did work. Below is an example
def show
#person = Person.find(params[:id])
respond_to do |format|
format.xml { render :text => #person.to_xml(:except => [:phone]) }
end
end
The except is good, but you have to remember to put it everywhere. If you're putting this in a controller, every method needs to have an except clause. I overwrite the serializable_hash method in my models to exclude what I don't want to show up. This has the benefits of not having t put it every place you're going to return as well as also applying to JSON responses.