Generating JSON with Rails? - ruby-on-rails

I just need to generate a JSON string that looks something like:
def self.feedback_request(history_event)
#event = history_event.event
#case_tracking_id = history_event.case_tracking_id
#request_type = "feedback"
return "{
"event":#event
"case_tracking_id":#case_tracking_id
"request_type":#request_type
"event_data":historic_event.to_json
}"
end
Does rails have some way to generate JSON strings?

The right way to do it is using the jbuilder which is part of Rails.
so from the documentation:
# app/views/message/show.json.jbuilder
json.content format_content(#message.content)
json.(#message, :created_at, :updated_at)
json.author do
json.name #message.creator.name.familiar
json.email_address #message.creator.email_address_with_name
json.url url_for(#message.creator, format: :json)
end
if current_user.admin?
json.visitors calculate_visitors(#message)
end
json.comments #message.comments, :content, :created_at
json.attachments #message.attachments do |attachment|
json.filename attachment.filename
json.url url_for(attachment)
end
This will build the following structure:
{
"content": "<p>This is <i>serious</i> monkey business</p>",
"created_at": "2011-10-29T20:45:28-05:00",
"updated_at": "2011-10-29T20:45:28-05:00",
"author": {
"name": "David H.",
"email_address": "'David Heinemeier Hansson' <david#heinemeierhansson.com>",
"url": "http://example.com/users/1-david.json"
},
"visitors": 15,
"comments": [
{ "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
{ "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
],
"attachments": [
{ "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
{ "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
]
}
So in you case your code should be something like:
json.(#event, #case_tracking_id, #request_type, historic_event)

Related

Why am I getting SON::ParserError trying to validate response using json_matchers?

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".

Converting a hash-inside-array to single key multiple value hash in ruby

I am trying to load data from redis db. I have a api only rails app and trying to render the json data as per requirement.
Currently I am able to get the data from redis in the following format.
[
{
"id": 1,
"name": "Stephenie Meyer",
"created_at": "2018-04-17T07:40:50.417Z",
"updated_at": "2018-04-17T07:40:50.417Z"
},
{
"id": 2,
"name": "V.C. Andrews",
"created_at": "2018-04-17T07:40:50.613Z",
"updated_at": "2018-04-17T07:40:50.613Z"
},
{
"id": 3,
"name": "Sophie Kinsella",
"created_at": "2018-04-17T07:40:50.646Z",
"updated_at": "2018-04-17T07:40:50.646Z"
}
]
How can convert this in a way such that the key value pairs of name,created and updated will be hash to a id key-value pair.
Into this
{"id": 1,
{
"name": "Stephenie Meyer",
"created_at": "2018-04-17T07:40:50.417Z",
"updated_at": "2018-04-17T07:40:50.417Z"
}
}
helper method for getting redis data.
def fetch_authors
authors = $redis.get('authors')
if authors.nil?
authors = Author.all.to_json
$redis.set("authors", authors).to_json
$redis.expire("authors", 5.hour.to_i)
end
JSON.load authors
end
And displaying on index page using
def index
#authors = fetch_authors
render json: #authors
end
The closest to what you want would probably be:
input = ...
input.map { |hash| [hash.delete(:id) || hash.delete('id'), hash] }.to_h
#⇒ {{1=>{:name=>...},
# {2=>{:name=>...},
# {3=>{:name=>...}}
Not exactly what you want because that's not correct syntax but you can achieve something similar with group_by
arr = [
{
"id": 1,
"name": "Stephenie Meyer",
"created_at": "2018-04-17T07:40:50.417Z",
"updated_at": "2018-04-17T07:40:50.417Z"
},
{
"id": 2,
"name": "V.C. Andrews",
"created_at": "2018-04-17T07:40:50.613Z",
"updated_at": "2018-04-17T07:40:50.613Z"
},
{
"id": 3,
"name": "Sophie Kinsella",
"created_at": "2018-04-17T07:40:50.646Z",
"updated_at": "2018-04-17T07:40:50.646Z"
}
]
arr.group_by { |e| e[:id] }
This will return
{
1 => [
{
:id => 1,
:name => "Stephenie Meyer",
:created_at => "2018-04-17T07:40:50.417Z",
:updated_at => "2018-04-17T07:40:50.417Z"
}
],
2 => [
{
:id => 2,
:name => "V.C. Andrews",
:created_at => "2018-04-17T07:40:50.613Z",
:updated_at => "2018-04-17T07:40:50.613Z"
}
],
3 => [
{
:id => 3,
:name => "Sophie Kinsella",
:created_at => "2018-04-17T07:40:50.646Z",
:updated_at => "2018-04-17T07:40:50.646Z"
}
]
}

How to custom status embed json in rails?

Here it's my products.controller
def index
if params[:page]
#product = Product.page(params[:page]).per(5)
else
#product = Product.order('updated_at DESC')
end
render json: {
status: '200',
message: 'OK',
data: ActiveModel::Serializer::CollectionSerializer.new(#product, each_serializer: ProductSerializer)},status: 200
end
def show
render json: {
status: '200',
message: 'OK',
data: ActiveModel::Serializer::CollectionSerializer.new(#product, each_serializer: ProductSerializer)},status: 200
end
Here my product serializer
class ProductSerializer < AplicationSerializer
attributes :id, :product_name, :category, :company, :description, :logo_img, :web_link
belongs_to :category
has_many :images
en
d
If I try to access localhost:3000/products/, it can display all the data that I want, but if I want to try localhost:3000/products/1, it's wrong, so what the wrong about my code?
{
"status": "200",
"message": "OK",
"data": [
{
"id": 1,
"product_name": "MDS",
"category": {
"id": 4,
"category": "Market Place",
"created_at": "2018-04-12T02:58:59.949Z",
"updated_at": "2018-04-12T02:58:59.949Z"
},
"company": "PT Media Data ",
"description": "ISP di Indo",
"logo_img": "mds.jpg",
"web_link": "https://mds.co/",",
"images": [
{
"id": 1,
"link": "http:/mds.com/mds.png"
},
{
"id": 2,
"link": "http:/mds.com/mds.png"
},
{
"id": 3,
"link": "http:/mds.com/mds.png"
},
{
"id": 4,
"link": "http:/mds.com/mds.png"
}
]
}
]
}
in the above is the display I want to display at http://localhost:3000/products/1, but i still got no appear, even though i can display it with same code on def index
Thanks for your help
The only thing that can seem to be missing here is setting the #product
If you have a before_action :show, :set_product this might not be the problem.
The other difference is between an array in the index and a single element in the show. you better use ProductSerializer.new(#product).as_json instead of using the collection serializer

Is there a better way to handle an Array response Rails 4

I am integrating with Scalable Press API. I am using HTTparty to handle the api response.
Example request:
curl "https://api.scalablepress.com/v2/products/gildan-sweatshirt-crew"
Example response:
{
"comments": "Generous fit. Soft, sturdy, easy to move around in, all the while looking good.",
"description": "Air Jet Spun Yarn. Double-needle stitching. Set-in sleeves. 1x1 Athletic Rib with Lycra(R). Quarter-turned to eliminate center crease.",
"name": "Gildan Sweatshirt - Crew",
"type": "Garment",
"properties": {
"brand": "Gildan",
"material": "7.75 oz 50% cotton, 50% polyester.",
"style": "18000"
},
"colors": [{
"name": "Kiwi",
"hex": "88b95d",
"images": [{
"url": "http://i1.ooshirts.com/images/lab_shirts/Kiwi-5-R.jpg",
"label": "Right"
}, {
"url": "http://i1.ooshirts.com/images/lab_shirts/Kiwi-5-L.jpg",
"label": "Left"
}, {
"url": "http://i1.ooshirts.com/images/lab_shirts/Kiwi-5-F.jpg",
"label": "Front"
}, {
"url": "http://i1.ooshirts.com/images/lab_shirts/Kiwi-5-B.jpg",
"label": "Back"
}],
"sizes": [
"sml",
"med",
"lrg",
"xlg",
"xxl",
"xxxl",
"xxxxl",
"xxxxxl"
]
}, {
"name": "Irish Green",
"hex": "3da858",
"images": [{
"url": "http://i1.ooshirts.com/images/lab_shirts/Irish-Green-5-F.jpg",
"label": "Front"
}, {
"url": "http://i1.ooshirts.com/images/lab_shirts/Irish-Green-5-L.jpg",
"label": "Left"
}, {
"url": "http://i1.ooshirts.com/images/lab_shirts/Irish-Green-5-R.jpg",
"label": "Right"
}, {
"url": "http://i1.ooshirts.com/images/lab_shirts/Irish-Green-5-B.jpg",
"label": "Back"
}],
"sizes": [
"sml",
"med",
"lrg",
"xlg",
"xxl",
"xxxl",
"xxxxl",
"xxxxxl"
]
}],
"additionalImages": [{
"label": "Front",
"url": "http://i1.ooshirts.com/products/5/front.jpg"
}, {
"label": "Back",
"url": "http://i1.ooshirts.com/products/5/back.jpg"
}, {
"label": "Collar",
"url": "http://i1.ooshirts.com/products/5/collar.jpg"
}],
"image": {
"label": "Catalog",
"url": "http://www.ooshirts.com/products/5/catalog.jpg"
},
"available": true,
"url": "https://api.scalablepress.com/v2/products/gildan-sweatshirt-crew",
"availabilityUrl": "https://api.scalablepress.com/v2/products/gildan-sweatshirt-crew/availability",
"productId": "gildan-sweatshirt-crew"
}
This response isn't too bad, but some products have upwards of 50 colors and each color has around 4 images.
Question:
I am looking to make my code a little better and easier to access the images. Is there a better way to handle the array?
View: <%= image_tag #product['colors'].to_a[0].to_a[2].to_a[1].to_a[1].to_a[0].to_a[1] %>
controller:
def show_product
#product = scalable_press.show_product(params[:product])
end
private
def scalable_press
ScalablePress.new
end
class ScalablePress
include HTTParty
base_uri 'https://api.scalablepress.com'
def initialize
#options = { basic_auth: { password: 'APIKEY' }, verify: false}
end
def products_in_category(category)
response = self.class.get("https://api.scalablepress.com/v2/categories/#{category}", #options)
response["products"]
end
def categories
response = self.class.get("https://api.scalablepress.com/v2/categories", #options)
end
def show_product(product)
response = self.class.get("https://api.scalablepress.com/v2/products/#{product}", #options)
# response["products"]
end
end

Rails - better flow control - loop

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" }

Resources