Related
I am creating a travel app which uses a backend Rails API. I've decided to use the Fast JSON API to serialize my data. I have a list of countries; each country has many cities, and each city has many attractions.
These are a list of my associations between my models.
Country.rb
has_many :cities
has_many :attractions, through: :locality
Localities.rb
has_many :attractions
belongs_to :country
Attraction.rb
belongs_to :locality
When I serialize my data for an individual attraction, I would like to include only the name attribute of the city and the name attribute of the country it belongs to. I am currently doing this by adding the optional parameter to include the locality and country name.
def show
attraction = Attraction.find_by(slug: params[:slug])
options = {}
options[:include] = [:locality, :'locality.country.name']
render json: AttractionSerializer.new(attraction, options).serialized_json
end
However, this gives all the attributes and relationships of the country, including a list of all unrelated localities nested within the country, which will become really inefficient when my dataset becomes larger. See below:
{
"data": {
"id": "1",
"type": "attraction",
"attributes": {
"name": "Plaza de EspaƱa",
"description": "Site of the World Exposition in 1929",
"types": null,
"latitude": 40.4232824,
"longitude": -3.7107257,
"slug": "plaza-de-espana",
"locality": {
"id": 1,
"name": "Seville",
"country_id": 168,
"created_at": "2020-06-10T05:43:47.474Z",
"updated_at": "2020-06-10T05:43:47.474Z",
"slug": "seville",
"latitude": 37.3886303,
"longitude": -5.9953403
}
},
"relationships": {
"locality": {
"data": {
"id": "1",
"type": "locality"
}
}
}
},
"included": [
{
"id": "1",
"type": "locality",
"attributes": {
"name": "Seville",
"latitude": 37.3886303,
"longitude": -5.9953403,
"slug": "seville"
},
"relationships": {
"country": {
"data": {
"id": "168",
"type": "country"
}
}
}
},
{
"id": "168",
"type": "country",
"attributes": {
"name": "Spain",
"slug": "spain",
"iso_3166_1_alpha2": "ES",
"iso_3166_1_alpha3": "ESP",
"iso_3166_1_numeric": "724"
},
"relationships": {
"localities": {
"data": [
{
"id": "1",
"type": "locality"
},
{
"id": "2",
"type": "locality"
},
{
"id": "3",
"type": "locality"
},
{
"id": "4",
"type": "locality"
},
{
"id": "5",
"type": "locality"
},
{
"id": "6",
"type": "locality"
}
]
},
"attractions": {
"data": [
{
"id": "1",
"type": "attraction"
}
]
}
}
}
]
}
Is there a way to only include just one attribute (i.e. name of Country) in the Attraction JSON, instead of the whole object? (Attraction is nested two levels below Country)
Thank you very much.
You need to create multiple serializers that work together to achieve this.
class AttractionSerializer
include FastJsonapi::ObjectSerializer
attributes :attraction_attr_1, :attraction_attr_2, etc.
belongs_to :locality, serializer: AttractionLocalitySerializer
end
class AttractionLocalitySerializer
include FastJsonapi::ObjectSerializer
attributes :name
belongs_to :country, serializer: AttractionCountrySerializer
end
class AttractionCountrySerializer
include FastJsonapi::ObjectSerializer
attributes :name
end
I am trying to compile an test.avsc avro schema file into java code.
Exception in thread "main" org.apache.avro.SchemaParseException: Can't redefine: test.record4
The idea is record4 should be the same type in name4 and name5
My test.avsc is:
{
"type":"record",
"namespace":"test",
"name":"record1",
"fields":[
{
"name": "orbject1",
"type":{
"type": "array",
"items":{
"type":"record", "name":"record2", "fields": [
{"name": "name1",
"type":{
"type": "array",
"items":{
"type":"record", "name":"record3", "fields": [
{"type": {
"type":"record", "name":"record4", "fields": [
{"name":"name2", "type":"long"}
]
},
"name":"name4"
},
{"type": {
"type":"record","name":"test.record4"
},
"name":"name5"
}
]
}
}
}
]
}
}
}
]
}
The test.record4 error is fixed if you rearrange the schema to look like this:
{
"type":"record",
"namespace":"test",
"name":"record1",
"fields":[
{
"name": "orbject1",
"type":{
"type": "array",
"items":{
"type":"record", "name":"record2", "fields": [
{"name": "name1",
"type":{
"type": "array",
"items":{
"type":"record", "name":"record3", "fields": [
{"type": {
"type":"record", "name":"record4", "fields": [
{"name":"name2", "type":"long"}
]
},
"name":"name4"
},
{"type": "test.record4", "name":"name5" }
]
}
}
}
]
}
}
}
]
}
I have an event reservation markup that works. I'm now trying to add a ViewAction but I'm getting a Modify Reservations CTA instead of View Tickets as shown on this page:
https://developers.google.com/gmail/markup/highlights#ticketed_event_reservation
The Modify Reservations CTA appears to be associated with Hotel Reservations, so I'm not sure why this is showing up for my event reservation type. I know the action.name doesn't change the CTA text but it's there to follow the code.
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "123456",
"reservationStatus": "http://schema.org/Confirmed",
"underName": {
"#type": "Person",
"name": "FIRSTNAME LASTNAME"
},
"reservationFor": {
"#type": "Event",
"name": "Michelle Branch",
"startDate": "2017-07-30 19:00:00.000",
"location": {
"#type": "Place",
"name": "Emos",
"address": {
"#type": "PostalAddress",
"streetAddress": "Emos",
"addressLocality": "Austin",
"addressRegion": "Texas",
"postalCode": "-----",
"addressCountry": "United States"
}
}
},
"ticketNumber": "123456",
"numSeats": "1",
"url": "URLHERE",
"action": {
"#type": "ViewAction",
"target": "URLHERE",
"url": "URLHERE",
"name": "View Order"
},
"description": "View Order"
}
</script>
I want to send out an email with a schema that defines two tickets.
The documentation states:
If you want to have one ticket (i.e. barcode) per individual and have
names for each individual on the ticket, create multiple
EventReservations (one per individual) with numSeats set to 1. The
example below shows what this looks like.
Sadly this doesn't work like that. If I use this schema (no seating, numSeats set to "1"):
<script type="application/ld+json">
[
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "E123456789",
"reservationStatus": "http://schema.org/Confirmed",
"underName": {
"#type": "Person",
"name": "John Smith"
},
"reservationFor": {
"#type": "Event",
"name": "Foo Fighters Concert",
"startDate": "2017-03-06T19:30:00-08:00",
"location": {
"#type": "Place",
"name": "AT&T Park",
"address": {
"#type": "PostalAddress",
"streetAddress": "24 Willie Mays Plaza",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94107",
"addressCountry": "US"
}
}
},
"numSeats": "1",
"ticketToken": "qrCode:AB34",
"ticketNumber": "abc123",
"ticketDownloadUrl": "http://..../ticket.pdf",
"ticketPrintUrl": "http://..../ticket.pdf"
},
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "E123456789",
"reservationStatus": "http://schema.org/Confirmed",
"underName": {
"#type": "Person",
"name": "Eva Green"
},
"reservationFor": {
"#type": "Event",
"name": "Foo Fighters Concert",
"startDate": "2017-03-06T19:30:00-08:00",
"location": {
"#type": "Place",
"name": "AT&T Park",
"address": {
"#type": "PostalAddress",
"streetAddress": "24 Willie Mays Plaza",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94107",
"addressCountry": "US"
}
}
},
"numSeats": "1",
"ticketToken": "qrCode:AB34",
"ticketNumber": "abc456",
"ticketDownloadUrl": "http://..../ticket.pdf",
"ticketPrintUrl": "http://..../ticket.pdf"
}
]
</script>
This will result in a mail in inbox that states that this reservation only contains one Ticket.
The only way to get inbox to state that the reservation contains two tickets is by adding a venueSeat.
E.g.:
<script type="application/ld+json">
[
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "E123456789",
"reservationStatus": "http://schema.org/Confirmed",
"underName": {
"#type": "Person",
"name": "John Smith"
},
"reservationFor": {
"#type": "Event",
"name": "Foo Fighters Concert",
"startDate": "2017-03-06T19:30:00-08:00",
"location": {
"#type": "Place",
"name": "AT&T Park",
"address": {
"#type": "PostalAddress",
"streetAddress": "24 Willie Mays Plaza",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94107",
"addressCountry": "US"
}
}
},
"numSeats": "1",
"venueSeat": "12",
"ticketToken": "qrCode:AB34",
"ticketNumber": "abc123",
"ticketDownloadUrl": "http://..../ticket.pdf",
"ticketPrintUrl": "http://..../ticket.pdf"
},
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "E123456789",
"reservationStatus": "http://schema.org/Confirmed",
"underName": {
"#type": "Person",
"name": "Eva Green"
},
"reservationFor": {
"#type": "Event",
"name": "Foo Fighters Concert",
"startDate": "2017-03-06T19:30:00-08:00",
"location": {
"#type": "Place",
"name": "AT&T Park",
"address": {
"#type": "PostalAddress",
"streetAddress": "24 Willie Mays Plaza",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94107",
"addressCountry": "US"
}
}
},
"numSeats": "1",
"venueSeat": "13",
"ticketToken": "qrCode:AB34",
"ticketNumber": "abc456",
"ticketDownloadUrl": "http://..../ticket.pdf",
"ticketPrintUrl": "http://..../ticket.pdf"
}
]
</script>
With this script the mail in inbox will correctly state that the reservation contains two tickets and will additionally print the two seats.
But in my case we do not have reserved seats, so I can't add this parameter.
Any ideas how to solve this or any plans from google to fix this?
Bonus question:
I wasn't able to actually see the ticket. Neither the QR-Code, nor a download link to the PDF. Any ideas why that is?
Based on the documentaiton "There are two options to do multiple tickets":
The first is change numSeats. This means a single reservation will represent tickets for numSeats number of individuals. This will be the option you want since you don't have reserved seating.
I used the following schema:
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "ABCD12345",
"reservationStatus": "http://schema.org/Confirmed",
"underName": {
"#type": "Person",
"name": "John Smith"
},
"reservationFor": {
"#type": "MusicEvent",
"name": "Foo Fighters Concert",
"url": "http://foofighterstour.com/SFO",
"performer": {
"#type": "Person",
"name": "The Foo Fighters",
"image": "http://www.amprocktv.com/wp-content/uploads/2013/01/foo-fighters-1-680x383.jpg"
},
"startDate": "2015-05-24T12:00:00-08:00",
"endDate": "2015-05-24T16:00:00-08:00",
"doorTime": "2015-05-24T11:00:00-08:00",
"location": {
"#type": "Place",
"name": "AT&T Park",
"address": {
"#type": "PostalAddress",
"streetAddress": "AT&T Park",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94107",
"addressCountry": "US"
}
}
},
"ticketDownloadUrl": "http://www.example.pdf",
"ticketPrintUrl": "http://www.example.pdf",
"modifyreservationurl": "http://www.example.pdf",
"ticketToken": "qrCode:AB34",
"ticketNumber": "abc12345",
"numSeats": "2"
}
</script>
I was able to generate 2 tickets in Inbox, create 2 Google Now cards, generate an action button (modify reservation) in Gmail and Inbox. The modify reservation action button leads to the ticket. Note I tried just using the "URL" property, to generate the "View Ticket" action button, but noticed it disappears. I was also able to generate the QRcode as well, however, the QRcode appeared to be broken on the second Now card.
*Update - the previous card screenshots were from my iphone using Google, the cards appear different on a Android device. One of the ticket properties (ticketdownloadurl / ticketprinturl) appeared when using an Android device:
I would like to fetch specific values in NSDictionnary with json data.
I would like to only fetch the first value for key "windspeedMiles" for example (in current_condition).
My Json data I've fetch is :
{
"data": {
"nearest_area": [
{
"distance_miles": "0.0",
"latitude": "54.500",
"longitude": "-8.500"
}
],
"request": [
{
"query": "Lat 54.50 and Lon -8.50",
"type": "LatLon"
}
],
"weather": [
{
"date": "2014-12-09",
"hourly": [
{
"cloudcover": "59",
"humidity": "84",
"precipMM": "0.1",
"pressure": "1024",
"sigHeight_m": "3.1",
"swellDir": "290",
"swellHeight_m": "3.0",
"swellPeriod_secs": "12.6",
"tempC": "5",
"tempF": "41",
"time": "0",
"visibility": "10",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "116",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0002_sunny_intervals.png"
}
],
"winddir16Point": "SSW",
"winddirDegree": "204",
"windspeedKmph": "34",
"windspeedMiles": "21"
},
{
"cloudcover": "84",
"humidity": "87",
"precipMM": "0.1",
"pressure": "1020",
"sigHeight_m": "0.6",
"swellDir": "240",
"swellHeight_m": "0.1",
"swellPeriod_secs": "12.4",
"tempC": "6",
"tempF": "42",
"time": "300",
"visibility": "10",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "119",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0003_white_cloud.png"
}
],
"winddir16Point": "SSW",
"winddirDegree": "193",
"windspeedKmph": "45",
"windspeedMiles": "28"
},
{
"cloudcover": "75",
"humidity": "91",
"precipMM": "0.4",
"pressure": "1016",
"sigHeight_m": "3.1",
"swellDir": "290",
"swellHeight_m": "3.0",
"swellPeriod_secs": "11.3",
"tempC": "7",
"tempF": "44",
"time": "600",
"visibility": "2",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "266",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0017_cloudy_with_light_rain.png"
}
],
"winddir16Point": "SSW",
"winddirDegree": "193",
"windspeedKmph": "54",
"windspeedMiles": "34"
},
{
"cloudcover": "0",
"humidity": "93",
"precipMM": "0.8",
"pressure": "1011",
"sigHeight_m": "1.0",
"swellDir": "250",
"swellHeight_m": "0.2",
"swellPeriod_secs": "10.6",
"tempC": "16",
"tempF": "61",
"time": "900",
"visibility": "10",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "113",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0001_sunny.png"
}
],
"winddir16Point": "SSW",
"winddirDegree": "202",
"windspeedKmph": "62",
"windspeedMiles": "39"
},
{
"cloudcover": "98",
"humidity": "95",
"precipMM": "6.6",
"pressure": "1006",
"sigHeight_m": "3.7",
"swellDir": "290",
"swellHeight_m": "3.6",
"swellPeriod_secs": "11.0",
"tempC": "18",
"tempF": "65",
"time": "1200",
"visibility": "7",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "302",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0018_cloudy_with_heavy_rain.png"
}
],
"winddir16Point": "SW",
"winddirDegree": "220",
"windspeedKmph": "64",
"windspeedMiles": "40"
},
{
"cloudcover": "89",
"humidity": "95",
"precipMM": "8.3",
"pressure": "1003",
"sigHeight_m": "4.3",
"swellDir": "290",
"swellHeight_m": "4.0",
"swellPeriod_secs": "10.9",
"tempC": "19",
"tempF": "65",
"time": "1500",
"visibility": "5",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "308",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0018_cloudy_with_heavy_rain.png"
}
],
"winddir16Point": "SW",
"winddirDegree": "234",
"windspeedKmph": "60",
"windspeedMiles": "38"
},
{
"cloudcover": "49",
"humidity": "73",
"precipMM": "1.5",
"pressure": "1004",
"sigHeight_m": "5.7",
"swellDir": "290",
"swellHeight_m": "5.3",
"swellPeriod_secs": "10.8",
"tempC": "7",
"tempF": "45",
"time": "1800",
"visibility": "10",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "353",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0009_light_rain_showers.png"
}
],
"winddir16Point": "W",
"winddirDegree": "261",
"windspeedKmph": "66",
"windspeedMiles": "41"
},
{
"cloudcover": "58",
"humidity": "73",
"precipMM": "0.5",
"pressure": "1005",
"sigHeight_m": "7.2",
"swellDir": "290",
"swellHeight_m": "6.7",
"swellPeriod_secs": "10.6",
"tempC": "5",
"tempF": "42",
"time": "2100",
"visibility": "10",
"waterTemp_C": "12",
"waterTemp_F": "53",
"weatherCode": "353",
"weatherIconUrl": [
{
"value": "http:\/\/cdn.worldweatheronline.net\/images\/wsymbols01_png_64\/wsymbol_0009_light_rain_showers.png"
}
],
"winddir16Point": "W",
"winddirDegree": "260",
"windspeedKmph": "79",
"windspeedMiles": "49"
}
],
"maxtempC": "19",
"mintempC": "5"
}
]
}
}
Here is my code :
Reports.m :
#import "Reports.h"
#interface Reports ()
#end
#implementation Reports
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://api.worldweatheronline.com/free/v2/weather.ashx?q=Bundoran&format=json&num_of_days=5&key=e1caa114b7fba6f5bcea272e1fc77"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *dico = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSDictionary *wind = [dico objectForKey:#"windspeedMiles"];
NSLog(#"The current windspeedMiles is : %#", wind);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
To grab that specific value in the structure you posted, you would access:
[[[[dico objectForKey:#"data"] objectForKey:#"current_condition"] objectAtIndex:0] objectForKey:#"windspeedMiles"]
You just need to look at your structure. When you get your dictionary with the JSONObjectWithData it will give you an NSDictionary for every set of curly braces, and an NSArray for every set of square ones.
Because everything in your JSON is a sub-object of "Data", I would recommend creating your original NSDictionary as:
NSDictionary *dico = [[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil] objectForKey:#"data"];
This way you don't have to keep referencing the "data" dictionary.
Your intended key resides in a nested NSDictionary object, so you can't retrieve it using:
NSDictionary *wind = [dico objectForKey:#"windspeedMiles"];
NSLog(#"The current windspeedMiles is : %#", wind);
Use:
NSDictionary *wind = [dico[#"data"][#"condition"] objectAtIndex:0];
NSLog(#"The current windspeedMiles is : %#", wind[#"windspeedMiles"]);