i use gem 'active_model_serializers', '~> 0.10.0' for formart json with gem versionist for version api manager
i write clone controller for export json like this :
#app/v1/products_controller
class V1::ProductsController < V1::BaseController
start_offset = params[:offset]
max_products = Product.all.size
products = Product.all.limit(Settings.limit_products_json).offset start_offset
next_number = start_offset.to_i + Settings.limit_products_json
if next_number < max_products
render json: {
products: products,
next_products: Settings.next_products_json + next_number.to_s,
product_end: Settings.product_end_false_json
}
else
render json: {
products: products,
product_end: Settings.product_end_true_json,
product_end_reason: Settings.product_end_reason_json
}
end
end
and in serializers folder i write:
#serializers/v1/product_serializer.rb
class V1::ProductSerializer < ActiveModel::Serializer
attributes :id, :name
end
and result is all attributes of Product to json. But I only want limit result of product to :id and :name as i wrote in class V1::ProductSerializer. How can i do that? Sorry for my bad english!
As far as I know active_model_serializers does not support versioning out of box. Either rename your serializer to ProductSerializer or specify each_serializer option explicitly and put your other parameters in meta:
meta = if next_number < max_products
{
next_products: Settings.next_products_json + next_number.to_s,
product_end: Settings.product_end_false_json
}
else
{
product_end: Settings.product_end_true_json,
product_end_reason: Settings.product_end_reason_json
}
end
render json: products, each_serializer: V1::ProductSerializer, meta: meta
Related
I have 2 tables, order and product_orders
they are related, in product_order it has the order_id
when I render the Json "render json: order", it comes out correct,
if I do "render json: p_order", it also outputs correct.
But I needed to generate the order json, with the items "quantity, unity_price and total from the Product_order table, how would I do that?
any suggestions or links for understanding/study?
def call_command
orders = Order.all
product_orders = ProductOrder.all
order = orders.map do |t|
build = { order_id: "#{t.id}",
created_at_id: "#{t.created_at}",
user_id: "#{t.user_id}",
desk_id: "#{t.desk_id}",
status: "#{t.status}",
subtotal: "#{t.subtotal}",
total: "#{t.total}"
}
end
p_order = product_orders.map do |p|
build = { #product_order_id: "#{p.id}",
# created_at_id: "#{p.created_at}",
order_id: "#{p.order_id}",
product_it: "#{p.product_id}",
quantity: "#{p.quantity}",
unity_price: "#{p.unit_price}",
total: "#{p.total}"
}
end
render json: order
end
Assuming that your Order and ProductOrder models are setup like this:
class Order < ActiveRecord::Base
has_many :product_orders
end
class ProductOrder < ActiveRecord::Base
belongs_to :order
end
You can use the includes in your render call, like the following:
#orders = Order.all
render json: #orders, include: ['product_orders']
You can also use the ActiveModel Serializers as #Benjamin suggested:
#orders.as_json(include: :product_orders)
it's a simple question
I have a controller
class Api::ColorsController < ApplicationController
def index
colors = ProductCustom.where(product_id: params[:product_id], wheel_id: params[:wheel_id])
render json: colors, each_serializer: ProductCustomsSerializer, adapter: :json, root: "data"
end
end
ant two serializers
class ProductCustomsSerializer < ActiveModel::Serializer
belongs_to :color, serializer: ColorSerializer
end
class ColorSerializer < ActiveModel::Serializer
attributes :id, :color
end
The response is fine but I'm getting nested objects. how can I prevent that?
{
"data":[
{
"color":{
"id":11,
"color":"green"
}
},
{
"color":{
"id":12,
"color":"blue"
}
}
]
}
what I want
{
"data":[
{
"id":11,
"color":"green"
},
{
"id":12,
"color":"blue"
}
]
}
As your controller name suggests and the output you are looking for it seems to indicate the outcome is to serialize Color objects not ProductCustom objects.
If that is the case based upon the params your controller is receiving and assuming there is a belongs_to relation from your ProductCustom to Color on your ActiveModel you may want to try:
class Api::ColorsController < ApplicationController
def index
# Query for the desired ProductCustoms objects and include the associated
# Color objects. From the result set, map the Color objects into the array
colors = ProductCustom
.includes(:color)
.where(product_id: params[:product_id], wheel_id: params[:wheel_id])
.map(&:color)
# You many want to add a trailing .uniq to the above if several ProductCustom
# use the same Color and you don't want duplicates.
# Note, Rails should be able to determine the serializer to use but you
# can always specify `each_serializer: ColorSerializer` if you really want
render json: colors, adapter: :json, root: "data"
end
end
At the time my controller looks like this:
def search
#icd4 = Icd4Code.search_full(params[:search]).first(20)
render json: { icd: #icd4.as_json(:only => [:bezeichnung, :nummer, :id])}
end
What i would like to change is that my code does not return #icd4.id as :id but instead #icd4.icd3_code_id as :id
So render json: { icd: #icd4 } would look like this:
{"icd":[{"id":6,"nummer":"A00.1","bezeichnung":"Cholera","icd3_code_id":3,"created_at":"2014-02-28T19:38:20.530Z","updated_at":"2014-02-28T19:38:20.530Z"},{"id":7,"nummer":"A00.1","bezeichnung":"El-Tor-Cholera","icd3_code_id":3,"created_at":"2014-02-28T19:38:20.533Z","updated_at":"2014-02-28T19:38:20.533Z"}]}
My actual code render json: { icd: #icd4.as_json(:only => [:bezeichnung, :nummer, :id])} returns this:
{"icd":[{"id":6,"nummer":"A00.1","bezeichnung":"Cholera"},{"id":7,"nummer":"A00.1","bezeichnung":"El-Tor-Cholera"}]}
And i would like this output:
{"icd":[{"id":3,"nummer":"A00.1","bezeichnung":"Cholera"},{"id":7,"nummer":"A00.1","bezeichnung":"El-Tor-Cholera"}]}
How can i achieve this? Thanks
Without a serializer you can iterate through the items and their keys and rename the key when you find yours.
#icd4 = Icd4Code.search_full(params[:search]).first(20)
data = #icd4.as_json(:only => [:bezeichnung, :nummer, :icd3_code_id]).tap do |icd4_json|
icd4_json.each do |icd4_item|
icd4_item.each do |key|
icd4_item[ 'id' ] = icd4_item.delete( key ) if key == 'icd3_code_id'
end
end
end
render json: { icd4: data }
You should definitely take a look at draper and active_model_serializers gems.
http://railscasts.com/episodes/409-active-model-serializers
http://railscasts.com/episodes/286-draper
although I use Draper in a bit different way then Ryan Bates does, usually I do something like this:
render json: item.decorate.as_json
for example as a simplest solution you could have this class:
class Icd4CodeDecorator < Draper::Decorator
decorates :icd4_code
delegate_all
def as_json(options={})
{
id: icd3_code_id,
bezeichnung: bezeichnung,
nummer: nummer
}
end
end
and then in your controller you could just do:
render json: #icd4.decorate.as_json
Although I think it would be better to keep things correct in as_json method and have id value returned for id property and create a decorator class inherited from Draper::CollectionDecorator and define there your custom method, something like:
class Icd4CodesDecorator < Draper::CollectionDecorator
def as_search_json
object.map do |o|
{
id: icd3_code_id,
bezeichnung: bezeichnung,
nummer: nummer
}
end
end
end
and then in your controller you could do:
render json: Icd4CodesDecorator.new(#icd4).as_search_json
This way you can easily create and maintain any number of versions of json output for your models.
The simplest way is to cleverly change the value something like this
def search
#icd4 = Icd4Code.search_full(params[:search]).first(20)
r = icd: #icd4.as_json(:only => [:bezeichnung, :nummer, :icd3_code_id])
final_value = []
r["icd"].each do |h|
f = {}
h.map do |k,v|
if k == 'icd3_code_id'
f["id"] = v
else
f[k] = v
end
end
final_value << f
end
render json: final_value
end
There is a model Event in my app and I have two problems, the first is the returned json that comes messed with the request:
$ curl http://0.0.0.0:3000/events
it gives me
{
"events":[
{"events":{"name":"First"}},
{"events":{"name":"Second"}}],
"meta":{"total_pages":9,
"next_page":"http://0.0.0.0:3000/events?page=2"}
}
which I think it should gives
{
"events":[
{"name":"First" },
{"name":"Second"}
],
"meta":{
"total_pages":9,
"next_page":"http://0.0.0.0:3000/events?page=2"
}
}
also I am using the gems draper and active_model_serializer, and the second problem is that the json format doesn't respect the Serializer definition:
class EventSerializer < ActiveModel::Serializer
attributes :id, :date_end
end
I would like to know where should I look to fix these problems.
Answering the questions, the code that generate the json:
class EventsController < ApplicationController
def index
#events = Event.order(:name).page(params[:page])
#events = #events.where(id: params[:ids].split(',')) if params[:ids].present?
render json: #events.decorate, meta: { total_pages: #events.total_pages, next_page: next_page_url(#events)}
end
def next_page_url(event)
unless event.last_page?
next_page = event.current_page + 1 unless event.last_page?
events_url(params.merge({:page => next_page}))
end
end
and the decorator:
class EventDecorator < Draper::Decorator
delegate :current_page, :total_pages, :limit_value
def name
object.name
end
end
I'm using Rails to query data and put it into a hash like so...
class AssignmentsController < ApplicationController
respond_to :json
def index
student = Student.find(current_user.student_id)
#assignments = Hash.new
#assignments["individual"] = Assignment.where(:student_id => student.id)
unless student.group_lesson_ids.nil?
student.group_lesson_ids.each do |g|
group_lesson = GroupLesson.find(g)
#assignments[group_lesson.name] = Assignment.where(:group_lesson_id => g)
end
end
end
end
Then I want Rabl to turn this into JSON to be used by a Marionette app.
Here's the Rabl file
object #assignments
attributes :id, :title, :student_id, :assigned
But when I inspect the JSON in the browser, it just shows me the ActiveRecord relation.
{
"#<ActiveRecord::Relation::ActiveRecord_Relation_Assignment:0x007fa2956b43a8>": [
{ },
{ },
{ }
]
}
I understand this is because of the concept of lazy loading, but what should I do in this situation to make the JSON available to Marionette?
How about this, provided you have relationships between models specified (not tested since I'm not currently using RABL):
class AssignmentsController < ApplicationController
respond_to :json
def index
#student = current_user.student
end
end
RABL template:
object false
node :assignments do
child #student.assignments => :individual
#student.group_lessons.each do |gl|
node(gl.name) { gl.assignments }
end
end