Ruby map JSON multiple but not all attributes with RABL - ruby-on-rails

I have the following Rabl in my views:
node(:relations) do |p|
related = p.relations.pluck(:related_to_id)
Spree::Product.find(related)
end
This renders the following:
"relations": [
{
"product": {
"id": 2,
"name": "T-SHIRT",
"description": "Awesome T shirts"
"created_at": "..."
"updated_at: "..."
.
.
.
bunch of other columns that I don't need.
My question is how do I only grab :name and :description, so that the JSON output looks like:
"relations": [
{
"product": {
"name": "T-SHIRT",
"description": "Awesome T shirts"
}
]
I've tried mapping it, Spree::Product.find(related).map { |r| [r.name, r.description] }
But that returns only the values, like so:
"relations": [
"T-SHIRT",
"Awesome T shirts"
]
Thank you for your help!
UPDATE:
When I write:
child :related_products do
attributes :name, :description
end
I get:
"spree_relations": [
{}
]
Link to model:
https://github.com/spree-contrib/spree_related_products/blob/master/app/models/spree/relation.rb

Well, there probably multiple ways to do it.
You can use rails #as_json method.
node(:relations) do |p|
related = p.relations.pluck(:related_to_id)
Spree::Product.find(related).as_json(only: [:name, :description])
end
Or you can try to do it the rabl way.
child :related_products do
attributes :name, :description
end
But for this you might need to change your model a bit.

Related

Issue when rendering a Jbuilder json object as json

I am developing in student tracking website in RoR. In model I have following code to build json
self.as_json
json = Jbuilder.new do |j|
j.courses student_courses do |course|
j.(course, :id, :name)
j.students students, :name
end
end.target!
puts json
return json
end
My controller code is
render json: {
courses: course.as_json,
}
and produces
{"courses":[
"{\"id\": 1,\"name\": \"english\",\"students\": [{\"name\": \"ALison\"},{\"name\": \"Robert\"}]
},{...}... ]"
instead of
"courses" : [
{
"id": 1,
"name": "english",
"students": [
{"name": "ALison"},
{"name": "Robert"}]
}, {..},...
]
It is adding escape character(/) before every double quotes. How can I solve this issue
Hey you can use this to generate as alternative
course.to_json(:include => { :students => { :only => :name } })

Rails Active Model Serializers - JSON Api

I am using AMS version 0.10 and looking to use the json-api specification for rendering my responses. However, I am having difficultly rendering the 'included' key for my relationship data. I have the following setup:
products_controller.rb
class Api::V1::ProductsController < ApplicationController
...
respond_to :json
def show
respond_with Product.find(params[:id])
end
...
product_serializer.rb
class ProductSerializer < ActiveModel::Serializer
attributes :id, :title, :price, :published
has_one :user
end
user_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :email, :auth_token, :created_at, :updated_at
end
products_controller_spec.rb
before(:each) do
#product = FactoryGirl.create :product
get :show, params: { id: #product.id }
end
...
it "has the user as a embeded object" do
product_response = json_response
puts "&&&&&&&&&&&&&&&"
puts product_response #output below
#expect(product_response[:user][:email]).to eql #product.user.email
end
...
json_response
{:data=>{:id=>"1", :type=>"products", :attributes=>{..working..}, :relationships=>{:user=>{:data=>{:id=>"1", :type=>"users"}}}}}
I would like to know how to get the 'included' section for the nested resource.
Example (from http://jsonapi.org/format/#introduction)
{
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!"
},
"links": {
"self": "http://example.com/articles/1"
},
"relationships": {
"author": {
"links": {
"self": "http://example.com/articles/1/relationships/author",
"related": "http://example.com/articles/1/author"
},
"data": { "type": "people", "id": "9" }
}
}],
"included": [{
"type": "people",
"id": "9",
"attributes": {
"first-name": "Dan",
"last-name": "Gebhardt",
"twitter": "dgeb"
},
"links": {
"self": "http://example.com/people/9"
}
},
I have never used AMS before so any help will be greatly appreciated.
Many thanks
Just for anyone else the solution is here https://github.com/rails-api/active_model_serializers/blob/master/docs/jsonapi/schema.md.
Essentially i add the following to my controller action (GET products/1)
render json: product, include: params[:include]
This will allow the requesting system to determine whether they would like to include the nested models by adding the parameter include='user' for the api to process.
Thanks

Active Model Serializer not working with json_api adapter

I am trying to use custom serializers for the relationships in a serializer and the json_api adapter enabled. However the relationships are not serialized correctly (or, better, not at all displayed/serialized).
PostController.rb
def index
render json: Post.all, each_serializer: Serializers::PostSerializer
end
Serializer
module Api
module V1
module Serializers
class PostSerializer < ActiveModel::Serializer
attributes :title, :id
belongs_to :author, serializer: UserSerializer
has_many :post_sections, serializer: PostSectionSerializer
end
end
end
end
JSON output:
{
"data": [
{
"attributes": {
"title": "Test Title"
},
"id": "1",
"relationships": {
"author": {
"data": {
"id": "1",
"type": "users"
}
},
"post_sections": {
"data": [
{
"id": "1",
"type": "post_sections"
}
]
}
},
"type": "posts"
}
]
}
As you can see, the relationships are not fulfilled, which happens only if I specify a custom serializer for the relationships!!
If I do something like this:
module Api
module V1
module Serializers
class PostSerializer < ActiveModel::Serializer
attributes :title, :id
belongs_to :author # no custom serializer!
has_many :post_sections # no custom serializer!
end
end
end
end
The relationships are shown correctly, but not using a custom serializer...
What's the issue here ?
EDIT
According to the json API 1.0 Format, what I am getting back is the so-called resource identifier object.
The following primary data is a single resource identifier object that
references the same resource:
{ "data": {
"type": "articles",
"id": "1" } }
Is there a way to prevent getting resource identifier objects, and get the actual data instead ?
Relationships only returns id and type according to json-api exmaples. If you need to return more information about this relation you should add include option on your render action.
Ex.
PostController.rb
class PostsController < ApplicationController
def show
render json: #post, include: 'comments'
end
end
Serializers
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :content
has_many :comment, serializer: CommentSerializer
end
class CommentSerializer < ActiveModel::Serializer
attributes :id, :title, :content
end
JSON output:
{
"data": {
"id": "1",
"type": "post",
"attributes": {
"title": "bla",
"content": "bla"
},
"relationships": {
"comment": {
"data": [
{
"type": "comments",
"id": "1"
}
]
}
}
},
"included": {
{
"id": "1",
"type": "comments",
"attributes": {
"title": "test",
"content": "test"
}
}
]
}
Just to add to #Bruno Bacarini's answer, you may also include chained associations by using:
render #posts, include: ['authors.profile', 'comments']
source: joaomdmoura's comment on github

Active model serializers - custom adapter

I would like to refactor an existing rails API using active model serializers.
Unfortunately the existing API uses a slightly different JSON schema than any of the the existing adapters and I have been unable to recreate it using AMS.
The schema I am trying to recreate is like this:
{
"status": 0,
"message": "OK",
"timestamp": 1438940571,
"data": {
"contacts": [
{
"contact": {
"id": "1",
"first_name": "Kung Foo",
"last_name": "Panda",
"created_at": "2015-07-23T14:09:20.850Z",
"modified_at": "2015-08-04T15:21:36.639Z"
}
},
{
"contact": {
"id": "2",
"first_name": "Johnny",
"last_name": "Bravo",
"created_at": "2015-07-23T14:09:20.850Z",
"modified_at": "2015-08-04T15:21:36.639Z"
}
}
]
}
}
I am wondering is there a way to create a custom adapter for active model serializers, or otherwise create this schema.
Could just use a couple of serializers.
class MessageSerializer < ActiveModel::Serializer
attributes :status, :message, :timestamp, :data
# We could've just used that, were it not for nested hashes
# has_many :contacts, key: :data
attributes :data
def data
ActiveModel::ArraySerializer.new(object.contacts, root: 'contacts')
end
end
class ContactSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :created_at, :modified_at
def root
'contact'
end
end
There seems to be no better way to do that
Then somewhere in your controller:
render json: Message.serializer.new(#message, root: false)

Change variable name in jbuilder

I'm trying to get a JSON output using jbuilder that looks like this:
[{"correct_response": 0,
"section_id": 1,
"image_url": "https://850.s3.amazonaws.com/uploads/question/3/PreguntaWeb.png?AWSAccessKeyId=AKIAJSKXBBJ4URBWSPUQ&Signature=r8COJLWNWABfwlm6BQ4ZpPlvFGw%3D&Expires=1401509509",
"responses": [{
"responseA": "https://850.s3.amazonaws.com/uploads/response/1/alternativaA.png?AWSAccessKeyId=AKIAJSKXBBJ4URBWSPUQ&Signature=MkUUT7NuoHDH/BjiJdMiHV5f%2BB4%3D&Expires=1401509509"},
{"responseB": "https://850.s3.amazonaws.com/uploads/response/2/alternativaB.png?AWSAccessKeyId=AKIAJSKXBBJ4URBWSPUQ&Signature=EZ6KeqhzlwPGX1PAetvqR/GPH2M%3D&Expires=1401509509"},
{"responseC": "https://850.s3.amazonaws.com/uploads/response/3/alternativaC.png?AWSAccessKeyId=AKIAJSKXBBJ4URBWSPUQ&Signature=/Ntt6y4JrfVjjw0zpOKgIXtihvI%3D&Expires=1401509509"},
{"responseD": "https://850.s3.amazonaws.com/uploads/response/4/alternativaD.png?AWSAccessKeyId=AKIAJSKXBBJ4URBWSPUQ&Signature=Exrr0WTsSx2n3FixjwADiiwwPjM%3D&Expires=1401509509"},
{"responseAE": "https://850.s3.amazonaws.com/uploads/response/5/alternativaE.png?AWSAccessKeyId=AKIAJSKXBBJ4URBWSPUQ&Signature=udJ5jK/zG9ug8A6WwsnhYZRcsPk%3D&Expires=1401509509"}
]
}]
I think I'm close, but I don't know what is wrong with my code:
json.array!(#questions) do |json, question|
json.extract! question, :correct_response, :section_id, :image_url
json.responses question.responses do |response|
[ 'responseA', 'responseB', 'responseC', 'responseD', 'responseE' ].each { |letter|
response.set!(letter, response.image_url )
}
end
end
end
Someone has any suggestions?

Resources