app/models/author.rb:
class Author < ApplicationRecord
validates :name, presence: true,
uniqueness: { case_sensitive: false }
end
app/serializers/author_serializer.rb:
class AuthorSerializer < ActiveModel::Serializer
attributes :id, :name, :bio
end
spec/spec_helper.rb:
#...
require 'json_matchers/rspec'
JsonMatchers.schema_root = 'spec/support/api/schemas.author.json':
#...
spec/support/api/schemas/authors/show.json:
{
"id": "file:/authors/show.json#",
"type": "object",
"definitions": {
"authors": {
"description": "A collection of authors",
"example": [{ "id": "1", "name": "Name" }],
"type": "array",
"items": {
"$ref": "file:/author.json#"
}
}
},
"required": ["authors"],
"properties": {
"authors": {
"$ref": "#/definitions/authors"
}
}
}
spec/requests/authors_show_request_pec.rb:
RSpec.describe 'Authors', type: :request do
setup { host! 'api.example.com' }
describe 'GET /author/:id' do
let!(:author) { create(:author, id: 13, name: 'Name', bio: 'bio') }
it 'returns requested author' do
get author_path(13)
expect(response).to have_http_status(200)
author_from_response = JSON.parse(response.body)
expect(author_from_response['name']).to eq(author.name)
expect(author_from_response['bio']).to eq(author.bio)
expect(response).to match_json_schema('author')
end
end
end
Response body contains all expected data, but spec if falinig to validate matching response to json schema.
Json_matchers gem seems to be configured according to manual.
Error that appears:
JsonMatchers::InvalidSchemaError:
783: unexpected token at '}
'
Try removing the trailing commas. The ruby JSON parser does not like them.
Your JSON response should be:
{
"id": "file:/authors/index.json#",
"type": "object",
"definitions": {
"authors": {
"description": "A collection of authors",
"example": [{ "id": "1", "name": "Name" }],
"type": "array",
"items": {
"$ref": "file:/author.json#"
}
}
},
"required": ["authors"],
"properties": {
"authors": {
"$ref": "#/definitions/authors"
}
}
}
Notice no trailing commas after the "items", "authors" nor "properties".
I have a few conditions where don't want to serialize the current object and want to skip it. But i haven't found a way to do that so I am ignoring attributes on attribute :foo, if: :condition. And this is generating empty {} in my serialized object inside arrays. How do I fix this?
[
{
"id": 392027,
"name": "ISC Board",
"grades":[
{
"id": 333938,
"name": "1",
"subjects": [
{
"id": 571671,
"subject": "Math"
},
{
"id": 742980,
"subject": "Science"
},
{
"id": 186926,
"subject": "English"
},
{
"id": 658224,
"subject": "Social_Studies"
},
{},
{},
{}
]
},
{
"id": 333943,
"name": "2",
"subjects": [
{
"id": 571671,
"subject": "Math"
},
{
"id": 742980,
"subject": "Science"
},
{
"id": 186926,
"subject": "English"
},
{
"id": 658224,
"subject": "Social_Studies"
},
{},
{},
{}
]
},
]
},
{
"id": 666627,
"name": "NY Board",
"grades":[
{
"id": 333938,
"name": "1",
"subjects": [
{
"id": 571671,
"subject": "Math"
},
{
"id": 742980,
"subject": "Science"
},
{
"id": 186926,
"subject": "English"
},
{
"id": 658224,
"subject": "Social_Studies"
},
{},
{},
{}
]
},
{
"id": 432943,
"name": "2",
"subjects": [
{
"id": 571671,
"subject": "Math"
},
{
"id": 742980,
"subject": "Science"
},
{
"id": 186926,
"subject": "English"
},
{
"id": 658224,
"subject": "Social_Studies"
},
{},
{},
{}
]
},
]
}
]
serializer looks something like this-
class BoardSerializer < ActiveModel::Serializer
#some code
class GradeSerializer < ActiveModel::Serializer
has_many :subjects
#some code
class SubjectSerializer < ActiveModel::Serializer
attribute :id, if: :condition
attribute :name, key: :subject, if: :condition
def condition
#some code
#returns true or false
#will not return both :id and :subject if false- I want to
#skip this current object if condition fails. (returns {})
end
end
end
end
How do I simply skip the current object in the serializer or remove empty hashes? Thanks
Please, check if this is the expected result:
input.transform_values { |v| v.map {|e| e.transform_values { |vv| vv.class == Array ? vv.select { |ee| ee unless ee.empty? } : vv } } }
# => {:grades=>[{:id=>333938, :name=>"1", :subjects=>[{:id=>571671, :subject=>"Math"}, {:id=>742980, :subject=>"Science"}, {:id=>186926, :subject=>"English"}, {:id=>658224, :subject=>"Social_Studies"}]}]}
EDIT: to meet changes in OP question.
input.map { |e| e.transform_values { |v| v.is_a?(Array) ? v.map {|ee| ee.transform_values { |vv| vv.is_a?(Array) ? vv.select { |eee| eee unless eee.empty? } : vv } } : v } }
# => [{:id=>392027, :name=>"ISC Board", :grades=>[{:id=>333938, :name=>"1", :subjects=>[{:id=>571671, :subject=>"Math"}, {:id=>742980, :subject=>"Science"}, {:id=>186926, :subject=>"English"}, {:id=>658224, :subject=>"Social_Studies"}]}, {:id=>333943, :name=>"2", :subjects=>[{:id=>571671, :subject=>"Math"}, {:id=>742980, :subject=>"Science"}, {:id=>186926, :subject=>"English"}, {:id=>658224, :subject=>"Social_Studies"}]}]}, {:id=>666627, :name=>"NY Board", :grades=>[{:id=>333938, :name=>"1", :subjects=>[{:id=>571671, :subject=>"Math"}, {:id=>742980, :subject=>"Science"}, {:id=>186926, :subject=>"English"}, {:id=>658224, :subject=>"Social_Studies"}]}, {:id=>432943, :name=>"2", :subjects=>[{:id=>571671, :subject=>"Math"}, {:id=>742980, :subject=>"Science"}, {:id=>186926, :subject=>"English"}, {:id=>658224, :subject=>"Social_Studies"}]}]}]
You can use #select! for this matter:
input = {
"grades":
[
{
"id": 333938,
"name": "1",
"subjects":
[
{
"id": 571671,
"subject": "Math"
},
{
"id": 742980,
"subject": "Science"
},
{
"id": 186926,
"subject": "English"
},
{
"id": 658224,
"subject": "Social_Studies"
},
{},
{},
{}
]
}
]
}
input[:grades].first[:subjects].select! { |i| !i.empty? }
My swagger index DSL is responding with the api/v1/users.json generated from rake swagger:docs.
Api::V1::UsersController:
swagger_api :index do
summary 'Returns list of users'
notes '/api/v1/users'
end
def index
#users = User.all
render(json: { users: ActiveModel::ArraySerializer.new(#users, each_serializer: Api::V1::UserSerializer) })
end
And when I try go the the actual api documentation and run /api/v1/users.json call ("Try it out!"), I get the public api definition for the whole users api controller:
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"basePath": "http://localhost:3000",
"resourcePath": "users",
"apis": [
{
"path": "/api/v1/users.json",
"operations": [
{
"summary": "Returns list of users",
"notes": "/api/v1/users",
"nickname": "Api::V1::Users#index",
"method": "get"
}
]
},
{
"path": "/api/v1/users/{id}.json",
"operations": [
{
"summary": "Returns a user",
"notes": "/api/v1/users/:id",
"parameters": [
{
"paramType": "path",
"name": "id",
"type": "integer",
"description": "User Id",
"required": false
}
],
"nickname": "Api::V1::Users#show",
"method": "get"
}
]
}
],
"authorizations": null
}
Also, when I try the call in Postman, it returns an array of Users like I would expect.
I have the following code which is taking results from an api call and providing it to my front-end as json:
notes = { :notes => [] }
json['Response']['OperationResponse']['Notes']['Note'].each do |note|
notes[:notes] << [:user => note['User'], :time_stamp => note['TimeStamp'], :text => note['Text']]
end
render :json => notes.to_json
but I'm getting this format:
{
"notes": [
[
{
"time_stamp": "test",
"user": "test",
"text": "test"
}
],
[
{
"time_stamp": "test",
"user": "test",
"text": "test"
}
],
....
Instead of this desired format:
{
"notes": [
[
{
"time_stamp": "test",
"user": "test",
"text": "test"
},
{
"time_stamp": "test",
"user": "test",
"text": "test"
},
....
Try with
json['Response']['OperationResponse']['Notes']['Note'].each do |note|
notes[:notes] << {:user => note['User'], :time_stamp => note['TimeStamp'], :text => note['Text']}
end
You are pushing the element as an array [], use {} instead.
I am grabbing value data: name, uid, highschool_name, graduateschool_name like this:
def add_friends
facebook.get_connections("me", "friends", :fields => "name, id, education").each do |hash|
self.friends.where(:name => hash['name'],
:uid => hash['id'],
:highschool_name => hash['education']['school']['name'] unless hash["education"].blank?,
:graduateschool_name => hash['education']['school']['name'] unless hash["education"].blank?).
first_or_create
end
end
From an array of hash:
"education": [
{
"school": {
"id": "110703012290674",
"name": "Kunskapsgymnasiet Malmö"
},
"year": {
"id": "136328419721520",
"name": "2009"
},
"type": "High School"
},
{
"school": {
"id": "112812485399398",
"name": "Malmö University"
},
"year": {
"id": "118118634930920",
"name": "2012"
},
"concentration": [
{
"id": "104076956295773",
"name": "Computer Science"
}
],
"type": "Graduate School",
"classes": [
{
"id": "165093923542525",
"name": "Programmering",
"description": "Kursen fokuserar på metoder och tekniker vid utveckling av webbapplikationer med hjälp av HTML5."
}
]
}
],
EDIT:
This code dosent work. I would like to pick every hichschool and Graduate School from this array of hash and save it.
high_schools = response['education'].collect{|ed| ed['school']['name'] if ed['type'] == "High School" }
grad_schools = response['education'].collect{|ed| ed['school']['name'] if ed['type'] == "Graduate School" }