I am building a UI as part of a product to make it easy to choose, select and style Google fonts. I am challenged by variable fonts because I cannot find a good way to get info about these.
The developer API provides metadata for all Google Fonts via a large JSON string. However, it does not seem to contain any data that would allow a developer to discern which fonts are variable. They all “appear” to be standard fonts.
Is there a fast way to get such data? By fast, I am talking about something similar to Google Font’s developer API, but with data for the various variable fonts that would include:
Which fonts are variable?
Which axes do the variable fonts ship with?
Currently, the only recommended approach I’ve seen for exploring variable fonts and their axes is to load the fonts into a web page and use Firefox’s Font editor in the developer tools to manually get the data. But with the current 112 variable fonts in Google Fonts, it could take days to collect this info. So my question is:
Is there a faster way to get meta data for the variable fonts in Google Fonts?
I am working on a font picker plugin and I ran into a similar problem, so I started investigating the google fonts main distribution site until I found what I was looking for.
Google's fonts site executes a call to the following API endpoint.
https://fonts.google.com/metadata/fonts
Which returns the following text file.
)]}'{"axisRegistry": [
{
"tag": "FILL",
"displayName": "Fill",
"min": 0.0,
"defaultValue": 0.0,
"max": 1.0,
"precision": -2,
"description": "The Fill axis is intended to provide a treatment of the design that fills in transparent forms with opaque ones (and sometimes interior opaque forms become transparent, to maintain contrasting shapes). Transitions often occur from the center, a side, or a corner, but can be in any direction. This can be useful in animation or interaction to convey a state transition. The numbers indicate proportion filled, from 0 (no treatment) to 1 (completely filled).",
"fallbacks": [
{
"name": "Normal",
"value": 0.0
},
{
"name": "Filled",
"value": 1.0
}
]
} ...],"familyMetadataList": [{
"family": "Alegreya",
"displayName": null,
"category": "Serif",
"size": 425570,
"subsets": [
"menu",
"cyrillic",
"cyrillic-ext",
"greek",
"greek-ext",
"latin",
"latin-ext",
"vietnamese"
],
"fonts": {
"400": {
"thickness": 4,
"slant": 1,
"width": 6,
"lineHeight": 1.361
},
"400i": {
"thickness": 4,
"slant": 4,
"width": 6,
"lineHeight": 1.361
},
"500": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"500i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"600": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"600i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"700": {
"thickness": 7,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"700i": {
"thickness": 6,
"slant": 4,
"width": 6,
"lineHeight": 1.361
},
"800": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"800i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"900": {
"thickness": 8,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"900i": {
"thickness": 8,
"slant": 4,
"width": 6,
"lineHeight": 1.361
}
},
"axes": [
{
"tag": "wght",
"min": 400.0,
"max": 900.0,
"defaultValue": 400.0
}
],
"unsupportedAxes": [],
"designers": [
"Juan Pablo del Peral",
"Huerta Tipográfica"
],
"lastModified": "2021-02-11",
"dateAdded": "2011-12-19",
"popularity": 159,
"trending": 828,
"defaultSort": 164,
"androidFragment": null,
"isNoto": false
}...],...}
Please note that while the above looks like a JSON file, it will be treated as a text file, so you will have to remove this part )]}' from the top of the text file, so you can then parse it as a JSON file.
The only top-level property that matters (as far as your use case is concerned) is the "familyMetadataList" property, as the name implies it includes all the fonts metadata, which includes the axes any given font has.
You will have to loop on the "familyMetadataList" prop and see if the font's axes member has an array that is not empty, from there we can deduce that it is a variable font.
You can do something as simple as this to figure out which font is variable.
const variableFonts=[];
const googleFontJSON = {
"familyMetadataList": [
{
"family": "Alegreya",
"displayName": null,
"category": "Serif",
"size": 425570,
"subsets": [
"menu",
"cyrillic",
"cyrillic-ext",
"greek",
"greek-ext",
"latin",
"latin-ext",
"vietnamese"
],
"fonts": {
"400": {
"thickness": 4,
"slant": 1,
"width": 6,
"lineHeight": 1.361
},
"400i": {
"thickness": 4,
"slant": 4,
"width": 6,
"lineHeight": 1.361
},
"500": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"500i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"600": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"600i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"700": {
"thickness": 7,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"700i": {
"thickness": 6,
"slant": 4,
"width": 6,
"lineHeight": 1.361
},
"800": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"800i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"900": {
"thickness": 8,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"900i": {
"thickness": 8,
"slant": 4,
"width": 6,
"lineHeight": 1.361
}
},
"axes": [
{
"tag": "wght",
"min": 400.0,
"max": 900.0,
"defaultValue": 400.0
}
],
"unsupportedAxes": [],
"designers": [
"Juan Pablo del Peral",
"Huerta Tipográfica"
],
"lastModified": "2021-02-11",
"dateAdded": "2011-12-19",
"popularity": 159,
"trending": 828,
"defaultSort": 164,
"androidFragment": null,
"isNoto": false
},
{
"family": "Alegreya SC",
"displayName": null,
"category": "Serif",
"size": 381295,
"subsets": [
"menu",
"cyrillic",
"cyrillic-ext",
"greek",
"greek-ext",
"latin",
"latin-ext",
"vietnamese"
],
"fonts": {
"400": {
"thickness": 4,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"400i": {
"thickness": 4,
"slant": 4,
"width": 7,
"lineHeight": 1.361
},
"500": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"500i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"700": {
"thickness": 6,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"700i": {
"thickness": 6,
"slant": 3,
"width": 7,
"lineHeight": 1.361
},
"800": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"800i": {
"thickness": null,
"slant": null,
"width": null,
"lineHeight": 1.361
},
"900": {
"thickness": 8,
"slant": 1,
"width": 7,
"lineHeight": 1.361
},
"900i": {
"thickness": 8,
"slant": 3,
"width": 7,
"lineHeight": 1.361
}
},
"axes": [],
"unsupportedAxes": [],
"designers": [
"Juan Pablo del Peral",
"Huerta Tipográfica"
],
"lastModified": "2021-03-24",
"dateAdded": "2011-12-19",
"popularity": 436,
"trending": 249,
"defaultSort": 443,
"androidFragment": null,
"isNoto": false
}
]}; // The array of font meta data
googleFontJSON.familyMetadataList.forEach(font => {
if (font.axes.length) {
font.isVariable=true;
} else {
font.isVariable=false;
}
});
console.log(googleFontJSON);
How you analyze the data is of course entirely your own prerogative.
Good luck with your project, Mr.Steven.
You can also acquire more information about any given variable font's axes step through the axis registry prop found JSON file found at https://fonts.google.com/metadata/fonts.
Simply examine the precision prop.
For example, axes with a 0.1 step like "opsz" and "wdth" have their precision set to -1, axes with a 0.01 step like "CASL" and "MONO" have their precision set to -2.
"axisRegistry": [
{
"tag": "opsz",
"displayName": "Optical size",
"min": 6.0,
"defaultValue": 14.0,
"max": 144.0,
"precision": -1, //<=== Here
"description": "Adapt the ...",
"fallbacks": [
{
"name": "6pt",
"value": 6.0
},
{
"name": "7pt",
"value": 7.0
}...
]
},...
I love the answer from Stranger1586. But I really also need data on the steps for each axis in order to properly build UI elements such as sliders. So I decided to write a scraper to scrape the data from https://fonts.google.com/variablefonts. That page contains updated data on all variable fonts and all supported axes according to Google Font's GitHub page.
The scraper creates a JSON file with axes data for each font family. I hope it might be helpful to others having the same need. Here is the code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.firefox.options import Options
from bs4 import BeautifulSoup
import json
def get_variable_fonts_data():
print('Opening: Google Variable Fonts page...')
options = Options()
options.headless = True
gecko_path = r'D:\Anaconda3\envs\py37\Lib\site-packages\helium\_impl\webdrivers\windows\geckodriver.exe'
url = 'https://fonts.google.com/variablefonts'
browser = webdriver.Firefox(options=options, executable_path=gecko_path)
browser.get(url)
timeout = 10 # seconds
# Wait for the table element as it is not part of the page source but is generated with JavaScript
try:
WebDriverWait(browser, timeout).until(EC.presence_of_element_located((By.TAG_NAME, 'table')))
print('Generating font table')
except TimeoutException:
print("Loading took too much time!")
soup = BeautifulSoup(browser.page_source, 'html.parser')
table = soup.find('table')
table_head = table.find('thead').find('tr')
header_values = []
for cell in table_head.find_all('th'):
header_values.append(cell.encode_contents().decode("utf-8").strip())
table_body = table.find('tbody')
variable_fonts_data = {}
for row in table_body.find_all('tr'):
axis_data = {}
cells = row.find_all('td')
font_family_name = cells[0].find('a').encode_contents().decode("utf-8").strip()
if not (font_family_name in variable_fonts_data):
variable_fonts_data[font_family_name] = {'Axes': {}}
axis_data[header_values[2]] = cells[2].encode_contents().decode("utf-8").strip() # Default
axis_data[header_values[3]] = cells[3].encode_contents().decode("utf-8").strip() # Min
axis_data[header_values[4]] = cells[4].encode_contents().decode("utf-8").strip() # Max
axis_data[header_values[5]] = cells[5].encode_contents().decode("utf-8").strip() # Step
variable_fonts_data[font_family_name]['Axes'][cells[1].encode_contents().decode("utf-8").strip()] = axis_data
return variable_fonts_data
with open('google_variable_fonts.json', 'w') as fonts_file:
json.dump(get_variable_fonts_data(), fonts_file)
Related
I have a chart that gets updated with new data and if the config is "almost" the same (new subtitle, data slightly different, etc...but same number of data values) I'm finding the last bar gets moved on top of the first bar, over laying it. Color me baffled. I'm using 9.3.3 but have repro'd it in "current" in this jsfiddle:
https://jsfiddle.net/wxpe6v2r/28/
const chart = Highcharts.chart('container', {
"title": {
"text": "Top 10"
},
"subtitle": {
"text": "Everything",
"useHTML": true
},
"colors": [
"#F5827A",
"#FBB3AF"
],
"chart": {
"marginLeft": 60,
"marginRight": 60,
"spacingTop": 10,
"spacingRight": 0,
"spacingBottom": 8,
"spacingLeft": 10,
"zoomType": "",
"alignTicks": false,
"animation": true
},
"plotOptions": {
"series": {
"animation": true,
"shadow": false,
"borderWidth": 0,
"marker": {
"enabled": true,
"states": {
"hover": {
"enabled": false
}
}
}
}
},
"legend": {
"enabled": true
},
"series": [
{
"name": "Count",
"type": "column",
"data": [
4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9
]
},
{
"name": "Cumulative Percent",
"yAxis": 1,
"type": "line",
"data": [
18.18, 22.73, 27.27, 31.82, 36.36, 40.91, 45.45, 50, 54.55, 59.09, 100
]
}
],
"xAxis": {
"type": "category",
"title": {
"text": "File",
"enabled": false,
},
"categories": [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "Other"
]
},
"yAxis": [
{
"min": 0,
"max": 9,
"lineWidth": 1,
"allowDecimals": false,
"title": {
"text": "Count",
"rotation": 270,
"style": {
"fontWeight": "bold"
}
},
"labels": {
"enabled": true
},
"startOnTick": false,
"endOnTick": false
},
{
"min": 0,
"max": 100,
"gridLineWidth": 0,
"lineWidth": 1,
"opposite": true,
"title": {
"text": "Cumulative Percent",
"rotation": 270,
"style": {
"fontWeight": "bold"
}
},
"labels": {
"enabled": true,
}
}
],
});
document.getElementById('update').addEventListener('click', () => {
chart.update({
"title": {
"text": "Top 10"
},
"subtitle": {
"text": "Everything",
"useHTML": true
},
"colors": [
"#F5827A",
"#FBB3AF"
],
"chart": {
"marginLeft": 60,
"marginRight": 60,
"spacingTop": 10,
"spacingRight": 0,
"spacingBottom": 8,
"spacingLeft": 10,
"zoomType": "",
"alignTicks": false,
"animation": true
},
"plotOptions": {
"series": {
"animation": true,
"shadow": false,
"borderWidth": 0,
"marker": {
"enabled": true,
"states": {
"hover": {
"enabled": false
}
}
}
}
},
"legend": {
"enabled": true
},
"series": [
{
"name": "Count",
"type": "column",
"data": [
4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11
]
},
{
"name": "Cumulative Percent",
"yAxis": 1,
"type": "line",
"data": [
18.18, 22.73, 27.27, 31.82, 36.36, 40.91, 45.45, 50, 54.55, 59.09, 100
]
}
],
"xAxis": {
"type": "category",
"categories": [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "Other"
]
},
"yAxis": [
{
"min": 0,
"max": 11,
"lineWidth": 1,
"allowDecimals": false,
"title": {
"text": "Count",
"rotation": 270,
"style": {
"fontWeight": "bold"
}
},
"labels": {
"enabled": true
},
"startOnTick": false,
"endOnTick": false
},
{
"min": 0,
"max": 100,
"gridLineWidth": 0,
"lineWidth": 1,
"opposite": true,
"title": {
"text": "Cumulative Percent",
"rotation": 270,
"style": {
"fontWeight": "bold"
}
},
"labels": {
"enabled": true,
}
}
],
}
);
});
Just hit the update button and the "Other" bar is moved to the first position, overlaying the "A" bar.
Any suggestions on what I'm doing wrong are appreciated.
P.S. I have noticed after playing with the jsfiddle that it moves the bar to the first matching series[0] data value. That is, given series[0] of [4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9], that gets updated to [4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11], it puts the [10] bar (value 11) over the [0] bar (value 4). If I change the initial series[0] values to [5, 2, 1, 1, 1, 1, 1, 1, 1, 1, 9], upon update() it moves the value 11 bar to series[2], the first matching value. I don't get it.
Defining xAxis.categories without xAxis.type is enough and it resolves the issue.
However, the problem looks like a bug, so you can report it on Highcharts Github: https://github.com/highcharts/highcharts/issues
"xAxis": {
// "type": "category",
"title": {
"text": "File",
"enabled": false,
},
"categories": [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "Other"
]
}
Live demo: https://jsfiddle.net/BlackLabel/8nu9x6g5/
API Reference: https://api.highcharts.com/highcharts/xAxis.categories
My ruby on rails app is supposed to do some things whenever a product is deleted. According to Shopify's website here the response to products/delete is supposed to be a JSON object with information such as the product_id associated with the product that was deleted:
{
"id": 788032119674292922,
"title": "Example T-Shirt",
"body_html": null,
"vendor": "Acme",
"product_type": "Shirts",
"created_at": null,
"handle": "example-t-shirt",
"updated_at": "2021-07-01T14:08:43-04:00",
"published_at": "2021-07-01T14:08:43-04:00",
"template_suffix": null,
"published_scope": "web",
"tags": "example, mens, t-shirt",
"admin_graphql_api_id": "gid:\/\/shopify\/Product\/788032119674292922",
"variants": [
{
"id": 642667041472713922,
"product_id": 788032119674292922,
"title": "",
"price": "19.99",
"sku": "example-shirt-s",
"position": 0,
"inventory_policy": "deny",
"compare_at_price": "24.99",
"fulfillment_service": "manual",
"inventory_management": "shopify",
"option1": "Small",
"option2": null,
"option3": null,
"created_at": null,
"updated_at": null,
"taxable": true,
"barcode": null,
"grams": 200,
"image_id": null,
"weight": 200.0,
"weight_unit": "g",
"inventory_item_id": null,
"inventory_quantity": 75,
"old_inventory_quantity": 75,
"requires_shipping": true,
"admin_graphql_api_id": "gid:\/\/shopify\/ProductVariant\/642667041472713922"
},
{
"id": 757650484644203962,
"product_id": 788032119674292922,
"title": "",
"price": "19.99",
"sku": "example-shirt-m",
"position": 0,
"inventory_policy": "deny",
"compare_at_price": "24.99",
"fulfillment_service": "manual",
"inventory_management": "shopify",
"option1": "Medium",
"option2": null,
"option3": null,
"created_at": null,
"updated_at": null,
"taxable": true,
"barcode": null,
"grams": 200,
"image_id": null,
"weight": 200.0,
"weight_unit": "g",
"inventory_item_id": null,
"inventory_quantity": 50,
"old_inventory_quantity": 50,
"requires_shipping": true,
"admin_graphql_api_id": "gid:\/\/shopify\/ProductVariant\/757650484644203962"
}
],
"options": [
{
"id": 527050010214937811,
"product_id": 788032119674292922,
"name": "Title",
"position": 1,
"values": [
"Small",
"Medium"
]
}
],
"images": [
{
"id": 539438707724640965,
"product_id": 788032119674292922,
"position": 0,
"created_at": null,
"updated_at": null,
"alt": null,
"width": 323,
"height": 434,
"src": "\/\/cdn.shopify.com\/shopifycloud\/shopify\/assets\/shopify_shirt-39bb555874ecaeed0a1170417d58bbcf792f7ceb56acfe758384f788710ba635.png",
"variant_ids": [
],
"admin_graphql_api_id": "gid:\/\/shopify\/ProductImage\/539438707724640965"
}
],
"image": null
}
However, whenever I go to test it by actually deleting a product in the Shopify Admin interface, I'm only getting the id in my response. Anybody know why this is happening? My setup for the other webhooks is the exact same and I'm not having any other issues.
Seems like this is an open issue on the shopify_api gem for version 2021-01. I don't think you are doing anything wrong. It looks like nobody has responded in a while to the issue, you might want to try to upgrade to another version to see if they fixed it in any of the newer versions.
EDIT: According to a post from 3/2017 the expected behaviour from deleted endpoints is to only return the ID of the resource that was deleted. This could be why the issue on Github is being ignored.
I'm monitoring builds on TFS & VSTS and would like to know how to get the overall progress (in percentage) of a running build or release.
You could use Rest API Get build details with timeline.
GET https://{instance}/DefaultCollection/{project}/_apis/build/builds/{buildId}/timeline?api-version={version}
Which will return build timeline and some more detail info including a percentComplete result. Note: this is task level based just like the build log in webportal, not the entire build.
Sample response
{
"records": [
{
"id": "bcddc27d-c891-4209-85d6-387e155439b0",
"parentId": "045f4ce9-cb71-424f-84de-4ab19281dc70",
"type": "Task",
"name": "Build solution **\\*.sln",
"startTime": "2015-07-16T19:53:20.853Z",
"finishTime": "2015-07-16T19:53:28.567Z",
"currentOperation": null,
"percentComplete": 100,
"state": "completed",
"result": "succeeded",
"resultCode": null,
"changeId": 16,
"lastModified": "0001-01-01T00:00:00",
"workerName": "Hosted Agent",
"order": 2,
"details": {
"id": "ef959107-e566-4c28-8d9f-354d605dd400",
"changeId": 6,
"url": "https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c/_apis/build/builds/391/Timeline/ef959107-e566-4c28-8d9f-354d605dd400"
},
"errorCount": 0,
"warningCount": 1,
"url": null,
"log": {
"id": 2,
"type": "Container",
"url": "https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c/_apis/build/builds/391/logs/2"
},
"issues": [
{
"type": "warning",
"category": "General",
"message": "The MSBuild version parameter has been deprecated. Ignoring value: latest",
"data": {
"type": "warning"
}
}
]
},
{
"id": "b5bb4de7-a8ea-4c7d-8491-3f745bba7d1b",
"parentId": "045f4ce9-cb71-424f-84de-4ab19281dc70",
"type": "Task",
"name": "Get sources",
"startTime": "2015-07-16T19:53:07.057Z",
"finishTime": "2015-07-16T19:53:19.493Z",
"currentOperation": null,
"percentComplete": 100,
"state": "completed",
"result": "succeeded",
"resultCode": null,
"changeId": 13,
"lastModified": "0001-01-01T00:00:00",
"workerName": "Hosted Agent",
"order": 1,
"details": null,
"errorCount": 0,
"warningCount": 0,
"url": null,
"log": {
"id": 1,
"type": "Container",
"url": "https://fabrikam-fiber-inc.visualstudio.com/DefaultCollection/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c/_apis/build/builds/391/logs/1"
}
},
I'm not sure the best way of approaching this; I've got a generic system for requesting data objects from an api and returning json by using ActiveModelSerializers and it's been fantasticly simple.
For one class I need to return data formatted differently than the normal class serilization and unsure of the best approach. No matter what it seems that I'm going to have to have an 'elsif' for this one class in the return (which pains me a little bit).
Currently I've got a class named 'curve' which a user has_many of, and so requesting a user's curve gets me something like this:
[{
"id": 7,
"name": "A",
"angle": 30,
"date": "2017-05-23T01:52:00.589-04:00",
"direction": "left",
"top": "C1",
"bottom": "C4",
"risser": 3,
"sanders": 8
}, {
"id": 8,
"name": "B",
"angle": 0,
"date": "2017-05-23T01:52:56.107-04:00",
"direction": "right",
"top": "C5",
"bottom": "C6",
"risser": null,
"sanders": null
}, {
"id": 9,
"name": "A",
"angle": 22,
"date": "2017-05-25T01:56:00.656-04:00",
"direction": "right",
"top": "C3",
"bottom": "C5",
"risser": null,
"sanders": null
}, {
"id": 11,
"name": "C",
"angle": 3,
"date": "2017-05-26T01:57:08.078-04:00",
"direction": "right",
"top": "C4",
"bottom": "C7",
"risser": null,
"sanders": null
}]
But I actually need each to be grouped by the name like so:
[{
"name": "A",
"points": [{
"id": 7,
"name": "A",
"angle": 30,
"date": "2017-05-23T01:52:00.589-04:00",
"direction": "left",
"top": "C1",
"bottom": "C4",
"risser": 3,
"sanders": 8
}, {
"id": 9,
"name": "A",
"angle": 22,
"date": "2017-05-25T01:56:00.656-04:00",
"direction": "right",
"top": "C3",
"bottom": "C5",
"risser": null,
"sanders": null
}]
},
{
"name": "B",
"points": [{
"id": 8,
"name": "B",
"angle": 0,
"date": "2017-05-23T01:52:56.107-04:00",
"direction": "right",
"top": "C5",
"bottom": "C6",
"risser": null,
"sanders": null
}]
},
{
"name": "C",
"points": [{
"id": 11,
"name": "C",
"angle": 3,
"date": "2017-05-26T01:57:08.078-04:00",
"direction": "right",
"top": "C4",
"bottom": "C7",
"risser": null,
"sanders": null
}]
}
]
Now I know I can do group_by and fiddle with the response - but even then it won't be using the default Curve serializer. I could also create a custom GroupedCurve serializer and possibly process each curve with a CurveSerializer - but at that point isn't it just like getting the default array and doing a map, and constructing my own hashes?
What's the best / cleanest way of processing data from top to the bottom format?
UPDATE:
Something like the following 'does the job' but the job is dirty:
def self.reformat_curves(curves)
arr = []
curves.each do |i|
alpha = i[:name]
entry = arr.find{|chunk| chunk[:name]==alpha}
if entry.nil?
arr << {name: alpha, points: [i]}
else
entry[:points] << i
end
end
return arr
end
The problwm what iam facing is ..when ever iam passing the values like array inside the dictionyy..it is showing me the error -1005 connection was lost..and when ever i dont pass the values the response is getting successfully created but inthe server side database the ofiice price details and office contact information and office document is not saving ..can any one help me how to handle thanks in advance
[
{
"OfficePrice": [
{
"office": 1,
"making_charge": 1,
"wastage": 1,
"weight_by": 1,
"credit_period": 1,
"cartage_price_type": null,
"cartage_price": null,
"diamond_price": 1,
"amethyst_price": 1,
"amber_price": 1,
"sapphire_price": 1,
"emerald_price": null,
"ruby_price": null,
"id": 1,
"createdAt": "2016-04-15T08:41:08.000Z",
"updatedAt": "2016-04-16T14:18:39.000Z"
}
],
"OfficeContactPerson": [
{
"office": 1,
"contact_name": null,
"designation": "ASDF",
"department": "234",
"mobile": "1231231231",
"email": null,
"incharge_status": null,
"created_by": null,
"modified_by": null,
"id": 1,
"createdAt": "2016-04-15T08:41:08.000Z",
"updatedAt": "2016-04-16T14:18:39.000Z"
},
{
"office": 1,
"contact_name": null,
"designation": "ASDF",
"department": "ASDF",
"mobile": "1231231231",
"email": null,
"incharge_status": null,
"created_by": null,
"modified_by": null,
"id": 2,
"createdAt": "2016-04-15T08:41:08.000Z",
"updatedAt": "2016-04-16T14:18:39.000Z"
}
],
"OfficeBank": [
{
"office": 1,
"bank": 2,
"branch": null,
"city": null,
"account_type": 1,
"ifsc_code": "12123",
"account_number": "12234",
"account_name": "asdfasd",
"id": 3,
"createdAt": "2016-04-16T14:18:39.000Z",
"updatedAt": "2016-04-16T14:18:39.000Z"
}
],
"OfficeDocument": [
{
"office": 1,
"document_original": null,
"document_stored_name": null,
"id": 1,
"createdAt": "2016-04-15T08:41:08.000Z",
"updatedAt": "2016-04-16T14:18:39.000Z"
}
],
"city": {
"name": "Bengalore",
"id": 1,
"createdAt": null,
"updatedAt": "2016-04-16T16:02:53.000Z"
},
"state": {
"name": "Karnataga",
"id": 1,
"createdAt": null,
"updatedAt": "2016-04-16T16:02:53.000Z"
},
"district": {
"name": "BGL",
"id": 1,
"createdAt": null,
"updatedAt": "2016-04-16T16:02:53.000Z"
},
"name": "kkk",
"short_name": "asdf",
"shop_no": "1",
"door_no": "11",
"floor": "1",
"building": "1",
"street": "1",
"area": "1",
"main": "1",
"pincode": "1",
"telephone": "1",
"hallmarking": null,
"payment_by": null,
"delivered_to": null,
"active_status": null,
"delete_status": null,
"created_by": null,
"modified_by": null,
"office_photo_original": null,
"office_photo_stored_name": null,
"cin_path": null,
"vat": null,
"pan": null,
"others": "123123",
"id": 1,
"createdAt": "2016-04-15T08:41:08.000Z",
"updatedAt": "2016-04-16T14:18:39.000Z"
}
the dictionary can't save null values.
The NSDictionay format doesn't support null vales. Thats why its returning error.
The only possible solution for this is to update server database ,change null values to 0 or "NULL"(in double quotes). it will solve your issue.