I have a Rails application which displays nested form in json format.
In the JSON Response i am also displaying an id field which represent another table.
How to display name corresponding to that id what i am getting so that i can display both name and id in my json format.
My controller
show method
def show
#maintemplate = Maintemplate.find(params[:id])
respond_with (#maintemplate) do |format|
format.json { render :json => #maintemplate }
end
end
Thanks in advance....
Try this:
render :json => #maintemplate.to_json(:include => { :user => { :only => :name } } )
This will replace the user_id key with a user key and a value with only the name attribute of user, like this:
{
"user_id": "12"
"user": { "name": "..." }
...
}
You can then access the username in the json response with ["user"]["name"]. You can also access the user id with ["user_id"].
For more see the documentation on as_json.
Update:
Using the info provided in the comments, I think this is what you actually want:
render :json => #maintemplate.to_json(:include => { :routine => { :include => :user, :user => { :only => :name } } } )
Add to as_json method with the additional method-attributes you desire to the class in which you are calling.
class MainTemplate
...
def name
User.find(self.user_id).name
end
def as_json(options = {})
options[:methods] = :name
super(options)
end
end
Related
I have theses associations:
# Post
has_many :photos
# Photos
belongs_to :post
In my show action, in the post controller, I have this:
def show
#post = Post.find(params[:id])
#photos = #post.photos
render json: {post: #post.id }
end
However, I'd like the json to include the photos of the post, and get something like this:
{
post: 14,
photos {
photo1 {
url: /myURL/,
id: 1
},
photo1 {
url: /myURL/,
id: 2
}
}
}
I found many posts on how to do the opposite but not this. How should I approach this ?
You can do it this way:
render :json => #post, :include => [:photos => {:only => :url, :id}]
In my rails app i defined a specific JSON-Format in my model:
def as_json(options={})
{
:id => self.id,
:name => self.name + ", " + self.forname
}
end
And in the controller i simply call:
format.json { render json: #patients}
So now im trying to define another JSON-Format for a different action but i dont know how?
How do i have to define another as_json or how can i pass variables to as_json? Thanks
A very ugly method but you can refactor it for better readability:
def as_json(options={})
if options.empty?
{ :id => self.id, :name => self.name + ", " + self.forname }
else
if options[:include_contact_name].present?
return { id: self.id, contact_name: self.contact.name }
end
end
end
Okay, I should give you a better piece of code, here it is:
def as_json(options = {})
if options.empty?
self.default_json
else
json = self.default_json
json.merge!({ contact: { name: contact.name } }) if options[:include_contact].present?
json.merge!({ admin: self.is_admin? }) if options[:display_if_admin].present?
json.merge!({ name: self.name, forname: self.forname }) if options[:split_name].present?
# etc etc etc.
return json
end
end
def default_json
{ :id => self.id, :name => "#{self.name}, #{self.forname}" }
end
Usage:
format.json { render json: #patients.as_json(include_contact: true) }
By defining hash structure by 'as_json' method, in respective model class i.e User model in (Example 1), it becomes the default hash stucture for active record(i.e., user) in json format. It cannot be overridden by any inline definitions as defined in Example: 2
Example 1:
class User < ActiveRecord::Base
.....
def as_json(options={})
super(only: [:id, :name, :email])
end
end
Example: 2
class UserController < ApplicationController
....
def create
user = User.new(params[:user])
user.save
render json: user.as_json( only: [:id, :name] )
end
end
Therefore, in this example when create action is executed 'user' is returned in ("only: [:id, :name, :email]") format not as ("only: [:id, :name]")
So, options = {} are passed to as_json method to specifiy different format for different methods.
Best Practice, is to define hash structure as constant and call it everwhere it is needed
For Example
Ex: models/user.rb
Here, constant is defined in model class
class User < ActiveRecord::Base
...
...
DEFAULT_USER_FORMAT = { only: [:id, :name, :email] }
CUSTOM_USER_FORMAT = { only: [:id, :name] }
end
Ex: controllers/user.rb
class UserController < ApplicationController
...
def create
...
render json: user.as_json(User::DEFAULT_USER_FORMAT)
end
def edit
...
render json: user.as_json(User::CUSTOM_USER_FORMAT)
end
end
Cool!
I am trying Rabl, however, I seem to receive a practically empty json block.
require_dependency "api/application_controller"
module Api
class RentablePropertiesController < ApplicationController
respond_to :json
def index
#r = Core::RentableProperty.all
# render :text => #r.to_json --> note: this renders the json correctly
render "api/rentable_properties/index" #note: rabl here does not
end
end
end
index.json.rabl
collection #r
Output
[{"rentable_property":{}}]
Note: with a simply #r.to_json, it renders correctly:
[{"id":1,"description":"description","property_type_id":1,"created_at":"2013-08-22T19:04:35.000Z","updated_at":"2013-08-22T19:04:35.000Z","title":"Some Title","rooms":null,"amount":2000.0,"tenure":null}]
Any idea why rabl doesn't work?
The documentation of RABL (https://github.com/nesquena/rabl#overview) says that you need to precise what attributes you want to show in your JSON.
Their example:
# app/views/posts/index.rabl
collection #posts
attributes :id, :title, :subject
child(:user) { attributes :full_name }
node(:read) { |post| post.read_by?(#user) }
Which would output the following JSON or XML when visiting /posts.json:
[{ "post" :
{
"id" : 5, title: "...", subject: "...",
"user" : { full_name : "..." },
"read" : true
}
}]
I've looked at similar posts but can't seem to quite figure it out.
I have the following function which works just fine. The Listing model has a foreign key called price_id which maps to the Price model and its price_range column. Price_id is returned as part of the message object in the JSON response.
How can I return the corresponding price_range value from the association instead of the price_id value (as part of the message obj, and keep the other attributes)?
def update
#listing = Listing.find(params[:listing][:id])
#if params were passed in for updating
if #listing.update_attributes(params[:listing])
#should we return the whole thing or just what's needed?
json_response = {
"success" => #listing.save, #save to DB and assign true/false based on success...
"message" => #listing.attributes #USE attributes to show output the content of the #message obj, and not another object called "message"
}
respond_to do |format|
#json response
format.html { render:json => json_response }
format.xml { render :xml => #listing }
#normal response. Consider leaving this for now?
#format.html { render :action => "detail" } #refresh this page, with new data in it. Consider trying to use redirect instead?
#format.xml { head :ok }
end
end #end if
end
add a method in your Listing model with the price_range and call it in serializable_hash
class Listing
def price_range
price.price_range
end
end
Like explain on comment you can use delegate instead this method :
class Listing
delegate :prince_range, :to => price
end
In you controller you can now do :
json_response = {
"success" => #listing.save, #save to DB and assign true/false based on success...
"message" => #listing.serializable_hash(:methods => [:price_range])
}
Based on what I read in this article, you should be able to do this:
class Listing
def as_json
super(:include => :price)
end
end
Then in your controller:
json_response = {
"success" => #listing.save,
"message" => #listing.as_json
}
If I understand correctly, you want to add #listing.price.price_range value to the "message" ?
If so, try this:
"message" => #listing.attributes[:price_range] = #listing.price.price_range
In my controller i have:
#photo = Photo.find(:all)
respond_to do |format|
...
format.json { render :json => #photo.to_json)
end
so my response looks like:
{
"photo":
{
"updated_at":"2010-10-14T19:12:35Z",
"photo_file_size":206422,
"created_at":"2010-10-14T19:12:01Z"
}
},
{
"photo":
{
"updated_at":"2010-10-16T18:19:38Z",
"photo_file_size":83593,
"created_at":"2010-10-14T19:14:35Z"
}
}
how can i add an additional json key value pair for every photo block?
something like:
"photo":
{
"updated_at":"2010-10-14T19:12:35Z",
"photo_file_size":206422,
"created_at":"2010-10-14T19:12:01Z"
----> "created_at_b":"2010/10/14"
}
maybe :include option?
thanks!
to_json can be made to include the result of any method available on your model. For example you could add the following method to your model:
class Photo < ActiveRecord::Base
def created_at_b
# whatever you want to do
end
end
In your controller you add:
format.json { render :json => #photo.to_json(:methods=>[:created_at_b])
That should return the json that you're after.