TokyuRuby会議11 (2016-07-29) 発表のスライドです
#tqrk11
@tkawa
- 川村 徹
- プログラマ
- ソニックガーデン
- REST厨
-
Sendagaya.rb
- 毎週月曜 19:30-
- ゆるーいRubyコミュニティ
JSON-LDとは
コンピュータが理解できるLinked Dataを表すためのJSONベースのフォーマット
コンピュータが理解できる → Googleクローラが理解できる → リッチな検索結果
Googleにデータの意味を伝えるためのフォーマット(の1つ)として使われることが多い
- BreadcrumbList
- Recipe
- Product
- Article (NewsArticle, BlogPosting)
- Review
- Event
- SoftwareApplication
- ...
AMPでも使う
{
"@context": "http://schema.org/",
"@type": "Recipe",
"@id": "https://park.example.co.jp/recipe/card/708850",
"name": "豚肉と茄子の生姜焼き",
"image": "https://park.example.co.jp/_var/images/recipe-master/142518/708850.jpg",
"author": {
"@type": "Person",
"name": "キャシィ塚本",
"image": "https://park.example.co.jp/resources_sp/images/common/cathy.png",
"description": "四万十川料理専門学校の講師です。"
},
"publisher": {
"@type": "Organization",
"name": "EXAMPLE株式会社",
"url": "http://www.example.co.jp/",
"logo": {
"@type": "ImageObject",
"url": "https://park.example.co.jp/resources_sp/images/common/logo_examplepark.png"
}
},
"datePublished": "2017-06-08",
"dateModified": "2017-06-08",
"description": "「豚肉と茄子の生姜焼き」のレシピ・作り方です。",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "90",
"reviewCount": "16",
"bestRating": "100",
"worstRating": "80"
},
"recipeYield": "2(servings)",
"totalTime": "PT10M",
"recipeIngredient": [
"豚こま切れ肉90g",
"なす2個(160g)",
"片栗粉大さじ1",
"ごま油大さじ1",
"キャベツのせん切り2枚分(100g)"
],
"recipeInstructions": [
"(1)なすはタテ5mm幅の薄切りにする。豚肉、なすの表面に片栗粉をまぶす。",
"(2)フライパンにごま油を熱し、(1)の豚肉・なすを入れて火が通るまで焼く。",
"(3)そのままドォーン!!!!"
],
"recipeCuisine": "和風",
"nutrition": {
"@type": "NutritionInformation",
"calories": "248kcal",
"carbohydrateContent": "20.9g",
"cholesterolContent": "30mg",
"fiberContent": "2.6g",
"proteinContent": "12.9g",
"sodiumContent": "1,171mg"
}
}
これを <script type="application/ld+json">
の中に書くという仕様。
さて、Railsでどうやって実装しますか?
例えばモデルに書く
# app/models/recipe.rb
def to_jsonld
{
'@context': 'http://schema.org/',
'@type': 'Recipe',
'@id': recipe_url, # ← ?
'name': name,
'image': image_url, # ← ?
...
}.to_json
end
URLが出せない(出しづらい)
なぜならJSONもビューだから
JSONをビューとして扱う
# config/initializers/mime_types.rb
Mime::Type.register 'application/ld+json', :jsonld
URLに .jsonld
もしくは
リクエストヘッダ Accept: application/ld+json
で
jsonldフォーマットのビューテンプレートが使われる。
# 今回は必要ないが、フォーマットによって処理を変える場合
respond_to do |format|
format.html { ... }
format.jsonld { ... }
end
テンプレートは rails/jbuilder が定番
# app/views/recipes/show.jsonld.jbuilder
json.set! :@context, 'http://schema.org/'
json.set! :@type, 'Recipe'
json.set! :@id, recipe_url(@recipe)
json.name @recipe.name
json.image image_url(@recipe)
...
個人的にはDSLが慣れない。。
そこで amatsuda/jb
# app/views/recipes/show.jsonld.jb
{
'@context': 'http://schema.org',
'@type': 'Recipe',
'@id': recipe_url(@recipe),
name: @recipe.name,
image: image_url(@recipe),
...
}
Hashそのまま書ける!
- 普通にrubyで書く
- 返されたオブジェクトを
to_json
した文字列がrenderされる - jbuilderより速い
さらに
# app/views/recipes/show.jsonld.jb
{
'@context': 'http://schema.org',
'@type': 'Recipe',
'@id': recipe_url(@recipe),
name: @recipe.name,
image: image_url(@recipe),
author: {
'@type': 'Person',
name: @recipe.author.name,
image: image_url(@recipe.author),
description: @recipe.author.description
},
...
}
jb は jbuilder と同様にパーシャルが使えるので、ネストした author を……
パーシャルでDRY
# app/views/recipes/show.jsonld.jb
{
'@context': 'http://schema.org',
'@type': 'Recipe',
'@id': recipe_url(@recipe),
name: @recipe.name,
image: image_url(@recipe),
author: render(@recipe.author),
...
}
# app/views/authors/_author.jsonld.jb
{
'@type': 'Person',
name: author.name,
image: image_url(author),
description: author.description
}
recipe 以外のところでも author が再利用可能に
さらにパーシャル化
# app/views/recipes/show.jsonld.jb
{
'@context': 'http://schema.org',
'@id': recipe_url(@recipe)
}.merge(render(@recipe))
# app/views/recipes/_recipe.jsonld.jb
{
'@type': 'Recipe',
name: @recipe.name,
image: image_url(@recipe),
author: render(@recipe.author),
...
}
こうすれば recipe 自体も再利用可能(例えば recipe の List など)
HTMLのパーシャルの使い方と同じ
もちろんこの手法はWeb APIでも使えます
JSON-LDもWeb APIとして使えます
HTMLに埋め込むには
# app/helpers/application_helper.rb
def jsonld_script_tag
jsonld = controller.render_to_string(formats: :jsonld)
content_tag :script, jsonld.html_safe, type: Mime[:jsonld].to_s
rescue ActionView::ActionViewError => e
logger.error e.message
nil
ensure
# render_to_string のバグ回避 https://github.com/rails/rails/issues/14173
lookup_context.rendered_format = nil
end
controller.render_to_string
すると、オブジェクトを渡したりしなくても現在のリクエストの状態のままレンダリングした文字列が得られる