When using :methods in to_json, is there a way to rename the key? I'm trying to replace the real id with a base62 version of it, and I want the value of base62_id to have the key :id.
#obj.to_json(
:except => :id
:methods => :base62_id
)
I tried to do
#obj.to_json(
:except => :id
:methods => { :id => :base62_id }
)
but that didn't work.
Any advice?
The to_json serializer uses the name of the method as the key for serialization. So you can't use the methods option for this.
Unfortunately to_json method doesnt acceptblock` parameter, otherwise you could have done something similar to
#obj.to_json(:except => :id) {|json| json.id = base62_id }
So that leaves us with a ugly hack such as:
def to_json(options={})
oid, self.id = self.id, self.base62_id(self.id)
super
ensure
self.id = oid
end
Now to_json will return the expected result.
Related
I created a REST API with rails and use .to_json to convert the API output to json response. E.g. #response.to_json
The objects in the response contains created_at and updated_at fields, both Datetime
In the JSON response, both these fields are converted to strings, which is more costly to parse than unixtimestamp.
Is there a simple way I can convert the created_at and updated_at fields into unixtimestamp without having to iterate through the whole list of objects in #response?
[updated]
danielM's solution works if it's a simple .to_json. However, if I have a .to_json(:include=>:object2), the as_json will cause the response to not include object2. Any suggestions on this?
Define an as_json method on your response model. This gets run whenever you return an instance of the response model as JSON to your REST API.
def as_json(options={})
{
:id => self.id,
:created_at => self.created_at.to_time.to_i,
:updated_at => self.updated_at.to_time.to_i
}
end
You can also call the as_json method explicitly to get the hash back and use it elsewhere.
hash = #response.as_json
Unix timestamp reference: Ruby/Rails: converting a Date to a UNIX timestamp
Edit: The as_json method works for relationships as well. Simply add the key to the hash returned by the function. This will run the as_json method of the associated model as well.
def as_json(options={})
{
:id => self.id,
:created_at => self.created_at.to_time.to_i,
:updated_at => self.updated_at.to_time.to_i,
:object2 => self.object2,
:posts => self.posts
}
end
Furthermore, you can pass in parameters to the method to control how the hash is built.
def as_json(options={})
json = {
:id => self.id,
:created_at => self.created_at.to_time.to_i,
:updated_at => self.updated_at.to_time.to_i,
:object2 => self.object2
}
if options[:posts] == true
json[:posts] = self.posts
end
json
end
hash = #response.as_json({:posts => true})
In my API, I am converting an ActiveRecord object into json via:
user.to_json :methods => :new_messages
Using irb, when I execute this statement, I get:
{someAttr: someValue, ....}
which is perfect. This is a single object so it's not wrapped in an array. Now when I run this in sinatra app like this:
get '/api/users/:fb_id' do |fb_id|
user = User.where :fb_id => fb_id
user.to_json :methods => :new_cookies
end
It wraps it in an array!!! Like this:
[{someAttr: someValue, ....}]
How can I fix this, and more importantly, why?!?
Simply using Hash.[]
Hash[{a: :b}]
# => {:a=>:b}
and more importantly, why?!?
Which ORM are you using in the second example? If it's ActiveRecord, then User.where :fb_id => fb_id returns ActiveRecord::Relation object which wraps into an array when you call .to_json. It can be fixed like so
get '/api/users/:fb_id' do |fb_id|
user = User.find_by_fb_id(fb_id)
user.to_json :methods => :new_cookies
end
replace this line:
user = User.where :fb_id => fb_id
with this line:
user = User.find_by_fb_id fb_id
In a rails app I have an action that returns a json representation of a collection of different models. It looks something like this:
respond_to :json
def index
#cars = Car.all
#vans = Van.all
respond_with({
:cars => #cars,
:vans => #vans
})
end
However, I want to customise the attributes and methods that are passed to the json object. A bit like:
respond_with({
:cars => #cars.to_json(:only => [:make, :model], :methods => [:full_name]),
:vans => #vans
})
Doing the above, causes the json representation of the "cars" to be escaped as one big string, like:
{
"cars":"[{\"car\":{\"make\":\"Ford\" ... etc
"vans": [{"van":{"make":"Citreon" ... vans not escaped
}
Obviously I'm approaching this the wrong way. Can anyone point me in the right direction?
Since you're nesting the to_json in another Hash, I think you need to use as_json (which returns a Hash instead of a String) instead:
respond_with({
:cars => #cars.as_json(:only => [:make, :model], :methods => [:full_name]),
:vans => #vans
})
I've got the following code
u = Client.get(:show_by_username, :username => username.downcase)
When a valid user is returned, they seem to be getting returned as a hash instead of an object that I can call methods on
e.g. I have to access values like
u['id']
instead of
u.id
How can I get it to return it as an object?
Thanks
As described in the docs for the ActiveResource 'get' method, it does not convert them into ActiveResource::Base instances. As it says, you need to use the find method instead:
u = Client.find(:all, :from => :show_by_username, :params => { :username => username.downcase })
I have my json serialization working fine
render :json => "#{current_object.serialize(:json, :attributes => [:id, :name])}
But I also want to add further data to the json before it gets set back to the client. Mainly the auth_token.
Googled around like crazy but I can not find what option serialize will take to allow me to append/merge my other data into the JSON.
Hopting to find something like this...
current_object.serialize(:json, :attriubtes => [:id, name], :magic_option => {:form_authenticity_token => "#{form_authenticity_token}"})
You want the :methods key, which works like :attributes, but will include the results of the methods given. In your case:
current_object.to_json(
:attributes => [:id, :name],
:methods => [:form_authenticity_token]
)
For what it's worth, in a recent Rails I hacked together what you want like this:
sr = ActiveRecord::Serialization::Serializer.new(your_object, some_serialization_options).serializable_record
sr['extra'] = my_extra_calculation(some_parameters)
format.json { render :json => sr }
Where your_object is what you want to serialize, some_serialization_options are your standard :include, :only, etc parameters, and my_extra_calculation is whatever you want to do to set the value.
Jimmy
Hacked it in and moving on...
current_object.serialize(:json, :attributes => [:id, :name]).gsub(/\}$/, ", \"form_authenticity_token\": \"#{form_authenticity_token}\"}")