はじめに
hkob の雑記録の第247回目は、引き続き NotionRubyMapping を 2025-09-03 に対応させるアップデートを記録していきます。
template block の削除
update_template_block_rta.sh を実行したら、Unsupported というレスポンスが返ってきました。そういえば随分前になくなったブロックでした。とりあえず、template block に関するファイルを一括で削除しました。その分テストも10個ほど減りました。retrieve 系、update 系はほぼスクリプトの修正が終わりました。
Finished in 0.99804 seconds (files took 0.78548 seconds to load) 2404 examples, 0 failures
search のテスト
create 系は準備が面倒なので、先に search をテストしました。database を検索しようとしていたので、エラーになっていました。このため、value の部分を data_source に変更しました。
#!/bin/sh
curl -X POST 'https://api.notion.com/v1/search' \\
-H 'Notion-Version: 2025-09-03' \\
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \\
-H 'Content-Type: application/json' \\
--data '{"filter":{"value":"data_source","property":"object"},"query":"Sample table"}'
スクリプトを実行するとこのようにエラーになりました。
1) NotionRubyMapping::Search exec Failure/Error: raise StandardError, json.inspect
data_source を検索しているので、object の data_source が存在せずエラーになっていたのでした。いよいよ DataSource を実装する時のようです。
# @param [Hash, Notion::Messages] json # @return [NotionRubyMapping::Base] def self.create_from_json(json) case json["object"] when "page" Page.new json: json when "database" Database.new json: json when "list" List.new json: json when "block" Block.decode_block json else raise StandardError, json.inspect end end
基本的に database が data_source に変更になるので、まず spec ファイルをコピーします。
cp spec/notion_ruby_mapping/blocks/{database,data_source}_spec.rb
ファイル中の Database → DataSource, database → data_source に変更していきます。当然、DataSource はまだ作っていないので、uninitialized constant になっています。
Failure/Error: RSpec.describe DataSource do let(:tc) { TestConnection.instance } let!(:nc) { tc.nc } describe "find" do subject { -> { DataSource.find data_source_id } } context "For an existing data_source" do let(:data_source_id) { TestConnection::DATABASE_ID } NameError: uninitialized constant NotionRubyMapping::DataSource
data_source を require するように blocks に登録します。
blocks: %w[base block database data_source list page url_caption_base_block bookmark_block breadcrumb_block text_sub_block_color_base_block bulleted_list_item_block callout_block child_base_block child_database_block child_page_block code_block column_list_block column_block divider_block embed_block equation_block file_base_block file_block heading1_block heading2_block heading3_block image_block toggle_heading1_block toggle_heading2_block toggle_heading3_block url_base_block link_preview_block link_to_page_block numbered_list_item_block paragraph_block pdf_block quote_block synced_block table_block table_row_block table_of_contents_block to_do_block toggle_block video_block],
data_source の取得
data_source がどういう扱いになるのか、現在の Database を調べてみます。
db = Database.find "c37a2c66e3aa4a0da44773de3b80c253" => NotionRubyMapping::Database-c37a2c66e3aa4a0da44773de3b80c253
この json を確認すると、database というコンテナの中に複数の data_source が複数存在することができるようになっています。data_source_id については URL の中には含まれず、この data_sources の配列から取得する必要があります。
db.json
=>
{"object" => "database",
"id" => "c37a2c66-e3aa-4a0d-a447-73de3b80c253",
"title" =>
[{"type" => "text",
"text" => {"content" => "Sample table", "link" => nil},
"annotations" =>
{"bold" => false,
"italic" => false,
"strikethrough" => false,
"underline" => false,
"code" => false,
"color" => "default"},
"plain_text" => "Sample table",
"href" => nil}],
"parent" =>
{"type" => "page_id", "page_id" => "c01166c6-13ae-45cb-b968-18b4ef2f5a77"},
"is_inline" => true,
"in_trash" => false,
"created_time" => "2022-02-07T21:29:38.416+00:00",
"last_edited_time" => "2025-09-01T06:31:12.223+00:00",
"data_sources" =>
[{"id" => "4f93db51-4e1d-4015-b07f-876e34c3b0b1", "name" => "Sample table"}],
"icon" => nil,
"cover" => nil,
"url" => "https://www.notion.so/c37a2c66e3aa4a0da44773de3b80c253",
"public_url" => "https://hkob.notion.site/c37a2c66e3aa4a0da44773de3b80c253",
"request_id" => "a517bb59-7c32-4b56-82a2-39de65f321da"}
ここで取得した data_source_id を DATA_SOURCE_ID として spec_helper.rb に追加しておきます。
# datasource_id DATA_SOURCE_ID = "4f93db514e1d4015b07f876e34c3b0b1"
create_from_json でも DataSource の作成を追加します。
# @param [Hash, Notion::Messages] json # @return [NotionRubyMapping::Base] def self.create_from_json(json) case json["object"] when "page" Page.new json: json when "data_source" DataSource.new json: json when "database" Database.new json: json when "list" List.new json: json when "block" Block.decode_block json else raise StandardError, json.inspect end end
順番にエラーをつぶしていきます。NotionCache に data_source がないと言われています。
NoMethodError: undefined method 'data_source' for #<NotionRubyMapping::NotionCache:0x000000013327e528>
database(id) をコピーして data_source(id) を作成します。
# @param [String] id data_source_id (with or without "-") # @return [NotionRubyMapping::Base] DataSource object or nil def data_source(id) object_for_key(id) { data_source_request id } end
この中で呼ばれている data_source_request を同様に追加します。
# @param [String] data_source_id # @return [Hash] response def data_source_request(data_source_id) request :get, data_source_path(data_source_id) end
data_source_path のテストは以下のようになります。
describe "data_source_path" do it { expect(nc.data_source_path("ABC")).to eq "v1/data_sources/ABC" } end
ここまで実行したところで、テストデータが足りないというエラーになっていました。ここから data_source に関するテストデータを準備していくことになります。
WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Please stub: GET https://api.notion.com/v1/data_sources/c7697137d49f49c2bbcdd6a665c4f921 with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer secret_J08RBf9SlofiMhuIeJZc6AnI5qHXwDOaq4RolJFaaZ0', 'Notion-Version'=>'2025-09-03', 'User-Agent'=>'Faraday v2.13.1'}
テストデータの取得
先ほどの data_source のテストデータを取得するために、retrieve_database_database.sh をコピーして修正します。
cp retrieve_database_database.sh retrieve_data_source_data_source.sh
スクリプトは以下のようになります。
curl 'https://api.notion.com/v1/data_sources/4f93db514e1d4015b07f876e34c3b0b1' \\
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \\
-H 'Notion-Version: 2025-09-03'
取得した JSON は以下のようになりました。興味があるのは、parent はコンテナに相当する database となり、その database の親は database_parent として別に用意されるようです。これらを取得できるようにメソッドを追加したいと思います。
{ "object": "data_source", "id": "4f93db51-4e1d-4015-b07f-876e34c3b0b1", "cover": null, "icon": { "type": "external", "external": { "url": "https://cdn.profile-image.st-hatena.com/users/hkob/profile.png" } }, "created_time": "2022-02-07T21:29:00.000Z", "created_by": { "object": "user", "id": "2200a911-6a96-44bb-bd38-6bfb1e01b9f6" }, "last_edited_by": { "object": "user", "id": "2200a911-6a96-44bb-bd38-6bfb1e01b9f6" }, "last_edited_time": "2025-09-01T06:31:00.000Z", "title": [ { "type": "text", "text": { "content": "Sample table", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Sample table", "href": null } ], "description": [], "is_inline": true, "properties": { "RelationTitle": { "id": "%3CnJT", "name": "RelationTitle", "description": null, "type": "relation", "relation": { "database_id": "1d6b1040-a9fb-48d9-9a3d-041429816e9f", "data_source_id": "f0a1bf33-7ff0-4d24-b5b6-efb3ea006b15", "type": "dual_property", "dual_property": { "synced_property_name": "Related to Sample table (Column)", "synced_property_id": "jZZ%3E" } } }, "MultiSelectTitle": { "id": "Kjx%7D", "name": "MultiSelectTitle", "description": null, "type": "multi_select", "multi_select": { "options": [ { "id": "2a0eeeee-b3fd-4072-96a9-865f67cfa6ff", "name": "Multi Select 1", "color": "yellow", "description": null }, { "id": "5f554552-b77a-474b-b5c7-4ae819966e32", "name": "Multi Select 2", "color": "default", "description": null }, { "id": "d4bc3d6e-a6e1-4d57-af66-d8ecbbda1dd3", "name": "multi_select", "color": "red", "description": null } ] } }, "LastEditedByTitle": { "id": "LQGa", "name": "LastEditedByTitle", "description": null, "type": "last_edited_by", "last_edited_by": {} }, "CheckboxTitle": { "id": "Lbi%5D", "name": "CheckboxTitle", "description": null, "type": "checkbox", "checkbox": {} }, "StatusTitle": { "id": "MNV~", "name": "StatusTitle", "description": null, "type": "status", "status": { "options": [ { "id": "dfd8a326-f149-4b01-b01a-57d8aed6de1b", "name": "Not started", "color": "default", "description": null }, { "id": "f17767fd-3186-4ba2-8d3a-01eef36e88ec", "name": "In progress", "color": "blue", "description": null }, { "id": "F<XA", "name": "Design", "color": "purple", "description": null }, { "id": "IRXI", "name": "Implementation", "color": "orange", "description": null }, { "id": "ceb89388-7f74-4bd5-a52d-0fd572a409f6", "name": "Done", "color": "green", "description": null } ], "groups": [ { "id": "2b356467-0400-420c-ad91-cdd5f98fc799", "name": "To-do", "color": "gray", "option_ids": [ "dfd8a326-f149-4b01-b01a-57d8aed6de1b" ] }, { "id": "ff88fa16-34b6-4818-ae5c-f8ce892d888b", "name": "In progress", "color": "blue", "option_ids": [ "IRXI", "f17767fd-3186-4ba2-8d3a-01eef36e88ec", "F<XA" ] }, { "id": "de6040ae-17d1-4dc7-939c-b7db49bcf482", "name": "Complete", "color": "green", "option_ids": [ "ceb89388-7f74-4bd5-a52d-0fd572a409f6" ] } ] } }, "DateTitle": { "id": "SPrp", "name": "DateTitle", "description": null, "type": "date", "date": {} }, "RollupTitle": { "id": "STe_", "name": "RollupTitle", "description": null, "type": "rollup", "rollup": { "rollup_property_name": "Tags", "relation_property_name": "RelationTitle", "rollup_property_id": ":>Fq", "relation_property_id": "<nJT", "function": "show_original" } }, "CreatedTimeTitle": { "id": "WsEj", "name": "CreatedTimeTitle", "description": null, "type": "created_time", "created_time": {} }, "LastEditedTimeTitle": { "id": "X%3E%40X", "name": "LastEditedTimeTitle", "description": null, "type": "last_edited_time", "last_edited_time": {} }, "Related to New database title(Added) (Relation)": { "id": "%5CaqD", "name": "Related to New database title(Added) (Relation)", "description": null, "type": "relation", "relation": { "database_id": "c7697137-d49f-49c2-bbcd-d6a665c4f921", "data_source_id": "34b5284f-60ac-4ec9-b168-224e4eaf68d2", "type": "dual_property", "dual_property": { "synced_property_name": "Relation", "synced_property_id": "N%60OG" } } }, "FormulaTitle": { "id": "%5D~iZ", "name": "FormulaTitle", "description": null, "type": "formula", "formula": { "expression": "now()" } }, "UserTitle": { "id": "_x%3E%3D", "name": "UserTitle", "description": null, "type": "people", "people": {} }, "CreatedByTitle": { "id": "eR%3D~", "name": "CreatedByTitle", "description": null, "type": "created_by", "created_by": {} }, "TextTitle": { "id": "flUp", "name": "TextTitle", "description": null, "type": "rich_text", "rich_text": {} }, "Related to Database created by API (Relation)": { "id": "iijV", "name": "Related to Database created by API (Relation)", "description": null, "type": "relation", "relation": { "database_id": "d25d3500-044d-4959-8564-10198038d651", "data_source_id": "a4a29073-fe60-4e10-adc6-92168a2fb8c9", "type": "dual_property", "dual_property": { "synced_property_name": "Relation", "synced_property_id": "nLjJ" } } }, "Related to New database title (Relation)": { "id": "mfBo", "name": "Related to New database title (Relation)", "description": null, "type": "relation", "relation": { "database_id": "c7697137-d49f-49c2-bbcd-d6a665c4f921", "data_source_id": "34b5284f-60ac-4ec9-b168-224e4eaf68d2", "type": "single_property", "single_property": {} } }, "MailTitle": { "id": "p%7Ci%3F", "name": "MailTitle", "description": null, "type": "email", "email": {} }, "File&MediaTitle": { "id": "qEdK", "name": "File&MediaTitle", "description": null, "type": "files", "files": {} }, "NumberTitle": { "id": "swq%5C", "name": "NumberTitle", "description": null, "type": "number", "number": { "format": "number_with_commas" } }, "UrlTitle": { "id": "tvis", "name": "UrlTitle", "description": null, "type": "url", "url": {} }, "SelectTitle": { "id": "zE%7C%3F", "name": "SelectTitle", "description": null, "type": "select", "select": { "options": [ { "id": "0fed8e50-c917-4b56-96d9-9691a5132fc4", "name": "Select 1", "color": "brown", "description": null }, { "id": "0b71c5a8-ea82-4b21-970e-b155e7c68a7e", "name": "Select 2", "color": "default", "description": null }, { "id": "b32c83bb-c9af-49e8-9b88-122139affdb7", "name": "Select 3", "color": "purple", "description": null } ] } }, "ID": { "id": "%7BGE%7C", "name": "ID", "description": null, "type": "unique_id", "unique_id": { "prefix": "ST" } }, "TelTitle": { "id": "%7CNHO", "name": "TelTitle", "description": null, "type": "phone_number", "phone_number": {} }, "Title": { "id": "title", "name": "Title", "description": null, "type": "title", "title": {} } }, "parent": { "type": "database_id", "database_id": "c37a2c66-e3aa-4a0d-a447-73de3b80c253" }, "database_parent": { "type": "page_id", "page_id": "c01166c6-13ae-45cb-b968-18b4ef2f5a77" }, "url": "https://www.notion.so/c37a2c66e3aa4a0da44773de3b80c253", "public_url": "https://hkob.notion.site/c37a2c66e3aa4a0da44773de3b80c253", "archived": false, "in_trash": false, "request_id": "a13d0fd8-5e2e-4974-b1ff-2cca15a2d37f" }
これらを取得するための stubs の読み込みに retrieve_data_source を追加します。
def generate_stubs WebMock.enable! retrieve_page retrieve_database retrieve_data_source (後略)
とりあえず DATA_SOURCE_ID の取得だけ stub を追加しました。
def retrieve_data_source generate_stubs_sub :get, __method__, :data_source_path, { data_source: [DATA_SOURCE_ID, 200], } end
これでこの Sample table を取得していたテストの大部分が通過しました。それ以外のものをつぶしていきます。
おわりに
database を除く retrive 系、update 系のテストデータ更新は終わっています。今回の主なアップデート目的である data_source について、順次修正していきます。やろうとしていることはほぼ解説したので、これ以外の細かい手順は解説を省略して作業を進めていきたいと思います。