はじめに
hkob の雑記録の第300回目は、NotionRubyMapping の v3.0.3 へのアップデートを解説します。今回は、Create page 時にテンプレートが指定できるようになったことへの対応です。
v3.0.2 へのアップデート
まず、template オプションを付けた shell script を作成しました。
curl '<https://api.notion.com/v1/pages>' \\
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \\
-H "Content-Type: application/json" \\
-H "Notion-Version: 2025-09-03" \\
--data '{
"parent": {
"data_source_id": "293d8e4e98ab80e7842e000befaa8ed5"
},
"template": {
"type": "template_id",
"template_id": "293d8e4e98ab80e8b622cd46b8ccb0cb"
},
"properties": {
"Name": {
"type": "title",
"title": [
{
"type": "text",
"text": {
"content": "New Page by data_source_id with template",
"link": null
},
"plain_text": "New Page by data_source_id with template",
"href": null
}
]
}
}
}'
シェルスクリプトを作成すると make するだけで、レスポンスの JSON が作成されるようになっています。
make
sh create_page_parent_data_source_with_template.sh > create_page_parent_data_source_with_template.json
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1710 0 1129 100 581 2139 1101 --:--:-- --:--:-- --:--:-- 3238
sleep 1
取得した JSON は以下のようになりました。
{ "object": "page", "id": "293d8e4e-98ab-81f9-b18d-e613fc770ebb", "created_time": "2025-10-21T23:09:00.000Z", "last_edited_time": "2025-10-21T23:09:00.000Z", "created_by": { "object": "user", "id": "40673a87-d8ed-41e0-aa55-7f0e8ace24cd" }, "last_edited_by": { "object": "user", "id": "40673a87-d8ed-41e0-aa55-7f0e8ace24cd" }, "cover": null, "icon": null, "parent": { "type": "data_source_id", "data_source_id": "293d8e4e-98ab-80e7-842e-000befaa8ed5", "database_id": "293d8e4e-98ab-807c-9513-da2359ef1748" }, "archived": false, "in_trash": false, "is_locked": false, "properties": { "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": { "content": "New Page by data_source_id with template", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "New Page by data_source_id with template", "href": null } ] } }, "url": "<https://www.notion.so/New-Page-by-data_source_id-with-template-293d8e4e98ab81f9b18de613fc770ebb>", "public_url": "<https://hkob.notion.site/New-Page-by-data_source_id-with-template-293d8e4e98ab81f9b18de613fc770ebb>", "request_id": "089c47a5-f6db-4901-a38e-aa63abe9bfd7" }
これを元にテストを作成します。テスト用のページタイトルは定数にしておきました。
PAGE_TITLE_FOR_CREATED_PAGE = "New Page by data_source_id" PAGE_TITLE_FOR_CREATED_PAGE_WITH_TEMPLATE = "New Page by data_source_id with template"
作成したテンプレートページの page_id も記録しておきます。
TEMPLATE_PAGE_ID = "293d8e4e98ab80e8b622cd46b8ccb0cb"
create のテストを複製し、これらを使った build_child_page、 create_child_page のテストを記述しました。それぞれに template_page オプションを追加しています。
describe "create with template" do create_page_title = { "properties" => { "Name" => { "title" => [ { "href" => nil, "plain_text" => PAGE_TITLE_FOR_CREATED_PAGE_WITH_TEMPLATE, "text" => { "content" => PAGE_TITLE_FOR_CREATED_PAGE_WITH_TEMPLATE, "link" => nil, }, "type" => "text", }, ], "type" => "title", }, }, } let(:parent_data_source) { DataSource.new id: TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID } let(:template_page) { instance_double Page, id: TestConnection::TEMPLATE_PAGE_ID } context "when build_child_page" do let(:target) do parent_data_source.build_child_page TitleProperty, "Name", template_page: template_page do |_, ps| ps["Name"] << PAGE_TITLE_FOR_CREATED_PAGE_WITH_TEMPLATE end end it { expect(target).to be_new_record } it_behaves_like "property values json", { "parent" => { "data_source_id" => TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID, }, "template" => { "type" => "template_id", "template_id" => TestConnection::TEMPLATE_PAGE_ID, }, }.merge(create_page_title) describe "dry_run" do let(:dry_run) { target.save dry_run: true } it_behaves_like "dry run", :post, :pages_path, json_method: :property_values_json end describe "create" do before { target.save } it_behaves_like "property values json", {} it { expect(target.id).to eq "293d8e4e98ab81f9b18de613fc770ebb" } it { expect(target).not_to be_new_record } end end context "create_child_page" do context "not dry_run" do let(:target) do parent_data_source.create_child_page TitleProperty, "Name", template_page: template_page do |_, ps| ps["Name"] << PAGE_TITLE_FOR_CREATED_PAGE_WITH_TEMPLATE end end it_behaves_like "property values json", {} it { expect(target.id).to eq "293d8e4e98ab81f9b18de613fc770ebb" } it { expect(target).not_to be_new_record } end context "dry_run" do let(:target) do parent_data_source.build_child_page TitleProperty, "Name", template_page: template_page do |_, ps| ps["Name"] << "New Page Title" end end let(:dry_run) do parent_data_source.create_child_page TitleProperty, "Name", template_page: template_page, dry_run: true do |_, ps| ps["Name"] << "New Page Title" end end it_behaves_like "dry run", :post, :pages_path, json_method: :property_values_json end end end
このオプションを受け付けるように Base の initialize に template_page オプションを追加しました。もともと、Payload の引数は parent だけでしたが、そこに template を追加することにしました。Payload は受け取った JSON はそのまま出力するので、Payload クラスは特に変更が必要ありませんでした。
def initialize(json: nil, id: nil, assign: [], parent: nil, template_page: nil) @nc = NotionCache.instance @json = json @id = @nc.hex_id(id || @json && @json["id"]) @archived = @json && @json["archived"] @has_children = @json && @json["has_children"] @new_record = true unless parent.nil? raise StandardError, "Unknown id" if !is_a?(List) && !is_a?(Block) && @id.nil? && parent.nil? payload_json = {} payload_json["parent"] = parent if !is_a?(Block) && parent payload_json["tempalte"] = {"type" => "template_page_id", "template_page_id" => template_page.id} if template_page @payload = Payload.new(payload_json) @property_cache = nil @created_time = nil @last_edited_time = nil return if assign.empty? assign.each_slice(2) { |(klass, key)| assign_property(klass, key) } @json ||= {} end
ここまでで property_values_json までのテストは通過しました。あとは WebMock の API 呼び出しのパラメータを追加するだけです。ここでは、最終引数に渡された payload が検出されると、 create_page_parent_data_source_with_template.json というファイルの内容が WebMock の返り値として返るように設定しています。これで、すべてのテストが通過しました。
parent_data_source_with_template: [nil, 200, { "properties" => { "Name" => { "type" => "title", "title" => [ { "type" => "text", "text" => { "content" => "New Page by data_source_id with template", "link" => nil, }, "plain_text" => "New Page by data_source_id with template", "href" => nil, }, ], }, }, "parent" => { "data_source_id" => "293d8e4e98ab80e7842e000befaa8ed5", }, "template" => { "type": "template_id", "template_id": TEMPLATE_PAGE_ID, }, }]
以上をもって、NotionRubyMapping の v3.0.2 をリリースしました。
I have released v3.0.2 of NotionRubyMapping. This morning, Notion API was updated to allow templates to be specified. Therefore, I have added a template_page option to create_child_page and build_child_page in NotionRubyMapping as well.#NotionRubyMappinghttps://t.co/ZQKirni7Ep
— hkob|Notion Ambassador (@hkob) 2025年10月22日
v3.0.3 へのアップデート
金曜日の座談会で、Notion API のアップデートを紹介したときに、 "type": "default" とすることでデフォルトテンプレートが設定できることに気づきました。ほぼ一緒なので、すぐに対応してみました。まずは、その設定をした shell script を作成しました。
curl '<https://api.notion.com/v1/pages>' \\
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \\
-H "Content-Type: application/json" \\
-H "Notion-Version: 2025-09-03" \\
--data '{
"parent": {
"data_source_id": "293d8e4e98ab80e7842e000befaa8ed5"
},
"template": {
"type": "default",
},
"properties": {
"Name": {
"type": "title",
"title": [
{
"type": "text",
"text": {
"content": "New Page by data_source_id with default template",
"link": null
},
"plain_text": "New Page by data_source_id with default template",
"href": null
}
]
}
}
}'
make すると、以下の JSON が取得できました。
{ "object": "page", "id": "297d8e4e-98ab-8179-ba96-cdd34784e3f3", "created_time": "2025-10-25T11:04:00.000Z", "last_edited_time": "2025-10-25T11:04:00.000Z", "created_by": { "object": "user", "id": "40673a87-d8ed-41e0-aa55-7f0e8ace24cd" }, "last_edited_by": { "object": "user", "id": "40673a87-d8ed-41e0-aa55-7f0e8ace24cd" }, "cover": null, "icon": null, "parent": { "type": "data_source_id", "data_source_id": "293d8e4e-98ab-80e7-842e-000befaa8ed5", "database_id": "293d8e4e-98ab-807c-9513-da2359ef1748" }, "archived": false, "in_trash": false, "is_locked": false, "properties": { "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": { "content": "New Page by data_source_id with default template", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "New Page by data_source_id with default template", "href": null } ] } }, "url": "<https://www.notion.so/New-Page-by-data_source_id-with-default-template-297d8e4e98ab8179ba96cdd34784e3f3>", "public_url": "<https://hkob.notion.site/New-Page-by-data_source_id-with-default-template-297d8e4e98ab8179ba96cdd34784e3f3>", "request_id": "a58190e2-a146-4867-811e-5188ccc3bdca" }
テストもコピーして修正しました。今回は、 template_page: "default" とすることで、デフォルトテンプレートを指定できるようにしました。
describe "create with default template" do create_page_title = { "properties" => { "Name" => { "title" => [ { "href" => nil, "plain_text" => PAGE_TITLE_FOR_CREATED_PAGE_WITH_DEFAULT_TEMPLATE, "text" => { "content" => PAGE_TITLE_FOR_CREATED_PAGE_WITH_DEFAULT_TEMPLATE, "link" => nil, }, "type" => "text", }, ], "type" => "title", }, }, } let(:parent_data_source) { DataSource.new id: TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID } context "when build_child_page" do let(:target) do parent_data_source.build_child_page TitleProperty, "Name", template_page: "default" do |_, ps| ps["Name"] << PAGE_TITLE_FOR_CREATED_PAGE_WITH_DEFAULT_TEMPLATE end end it { expect(target).to be_new_record } it_behaves_like "property values json", { "parent" => { "data_source_id" => TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID, }, "template" => { "type" => "default", }, }.merge(create_page_title) describe "dry_run" do let(:dry_run) { target.save dry_run: true } it_behaves_like "dry run", :post, :pages_path, json_method: :property_values_json end describe "create" do before { target.save } it_behaves_like "property values json", {} it { expect(target.id).to eq "297d8e4e98ab8179ba96cdd34784e3f3" } it { expect(target).not_to be_new_record } end end context "create_child_page" do context "not dry_run" do let(:target) do parent_data_source.create_child_page TitleProperty, "Name", template_page: "default" do |_, ps| ps["Name"] << PAGE_TITLE_FOR_CREATED_PAGE_WITH_DEFAULT_TEMPLATE end end it_behaves_like "property values json", {} it { expect(target.id).to eq "297d8e4e98ab8179ba96cdd34784e3f3" } it { expect(target).not_to be_new_record } end context "dry_run" do let(:target) do parent_data_source.build_child_page TitleProperty, "Name", template_page: "default" do |_, ps| ps["Name"] << "New Page Title" end end let(:dry_run) do parent_data_source.create_child_page TitleProperty, "Name", template_page: "default", dry_run: true do |_, ps| ps["Name"] << "New Page Title" end end it_behaves_like "dry run", :post, :pages_path, json_method: :property_values_json end end end
これに対応するために Base の initialize の部分を以下のように修正しました。
payload_json = {} payload_json["parent"] = parent if !is_a?(Block) && parent if template_page == "default" payload_json["template"] = {"type" => "default"} elsif template_page payload_json["template"] = {"type" => "template_id", "template_id" => template_page.id} end
これで、 property_values_json の作成まで通過したことを確認したので、WebMock の設定を追加しました。これでテストがすべて通過したことを確認しました。
parent_data_source_with_default_template: [nil, 200, { "properties" => { "Name" => { "type" => "title", "title" => [ { "type" => "text", "text" => { "content" => "New Page by data_source_id with template", "link" => nil, }, "plain_text" => "New Page by data_source_id with template", "href" => nil, }, ], }, }, "parent" => { "data_source_id" => "293d8e4e98ab80e7842e000befaa8ed5", }, "template" => { "type": "default", }, }],
これで NotionRubyMapping v3.0.3 としてリリースしました。
おわりに
今回は、Page 作成時のテンプレート指定に対応した NotionRubyMapping のアップデートについて解説しました。今後も Notion API に変更があるときには、NotionRubyMapping も付いていくつもりです。
https://hkob.notion.site/hkob-16dd8e4e98ab807cbe3cf3cc94cdfe0f?pvs=4