Skip to content

Commit 82d5305

Browse files
committed
CoderDojo RSSニュース管理システムの改善
レビューに対応: - 全置換方式→追記・更新方式に変更 - IDを古い順に連番で一意性確保 - published_at順ソートの実装 - IDをYAML出力の1行目に配置 主な変更点: • 既存記事のID保持: 新規追加時も既存IDは変更されない • 効率的な分類処理: 新規・更新・変更なしの3分類で最適化 • 詳細ログ出力: 新規X件、更新Y件を明確に表示 • 既存記事更新対応: タイトル・公開日変更の自動反映 • 安全性向上: Time.parseのrequire追加、エラーハンドリング強化 技術的改善: > 既存データをハッシュ化してO(1)検索に最適化 > 3つのアイテム分類(unchanged/updated/truly_new) > BroadcastLoggerでコンソール+ファイル出力 > formatted_itemsでYAML構造を整理
1 parent 71a1ab6 commit 82d5305

File tree

1 file changed

+63
-10
lines changed

1 file changed

+63
-10
lines changed

lib/tasks/fetch_news.rake

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'rss'
22
require 'open-uri'
33
require 'yaml'
4+
require 'time'
45
require 'active_support/broadcast_logger'
56

67
namespace :news do
@@ -13,6 +14,14 @@ namespace :news do
1314

1415
logger.info('==== START news:fetch ====')
1516

17+
# 既存の news.yml を読み込み
18+
yaml_path = Rails.root.join('db', 'news.yml')
19+
existing_news = if File.exist?(yaml_path)
20+
YAML.load_file(yaml_path)['news'] || []
21+
else
22+
[]
23+
end
24+
1625
# テスト/ステージング環境ではサンプルファイル、本番は実サイトのフィード
1726
feed_urls = if Rails.env.test? || Rails.env.staging?
1827
[Rails.root.join('spec', 'fixtures', 'sample_news.rss').to_s]
@@ -25,7 +34,7 @@ namespace :news do
2534
end
2635

2736
# RSS 取得&パース
28-
items = feed_urls.flat_map do |url|
37+
new_items = feed_urls.flat_map do |url|
2938
logger.info("Fetching RSS → #{url}")
3039
begin
3140
URI.open(url) do |rss|
@@ -44,19 +53,63 @@ namespace :news do
4453
end
4554
end
4655

47-
# 重複排除&日付降順ソート
48-
unique = items.uniq { |i| i['url'] }
49-
sorted = unique.sort_by { |i| i['published_at'] }.reverse
56+
# 既存データをハッシュに変換(URL をキーに)
57+
existing_items_hash = existing_news.index_by { |item| item['url'] }
5058

51-
# id を追加
52-
sorted.each { |i| i['id'] = i['url'] }
59+
# 新しいアイテムと既存アイテムを分離
60+
truly_new_items = []
61+
updated_items = []
62+
63+
new_items.each do |new_item|
64+
if existing_items_hash.key?(new_item['url'])
65+
# 既存アイテムの更新
66+
existing_item = existing_items_hash[new_item['url']]
67+
updated_item = existing_item.merge(new_item) # 新しい情報で更新
68+
updated_items << updated_item
69+
else
70+
# 完全に新しいアイテム
71+
truly_new_items << new_item
72+
end
73+
end
5374

54-
# YAML に書き出し
55-
File.open('db/news.yml', 'w') do |f|
56-
f.write({ 'news' => sorted }.to_yaml)
75+
# 既存の最大IDを取得
76+
max_existing_id = existing_news.map { |item| item['id'].to_i }.max || 0
77+
78+
# 新しいアイテムのみに ID を割り当て(古い順)
79+
truly_new_items_sorted = truly_new_items.sort_by { |item|
80+
Time.parse(item['published_at'])
81+
}
82+
83+
truly_new_items_sorted.each_with_index do |item, index|
84+
item['id'] = max_existing_id + index + 1
5785
end
5886

59-
logger.info("✅ Wrote #{sorted.size} items to db/news.yml")
87+
# 更新されなかった既存アイテムを取得
88+
updated_urls = updated_items.map { |item| item['url'] }
89+
unchanged_items = existing_news.reject { |item| updated_urls.include?(item['url']) }
90+
91+
# 全アイテムをマージ
92+
all_items = unchanged_items + updated_items + truly_new_items_sorted
93+
94+
# 日付降順ソート
95+
sorted_items = all_items.sort_by { |item|
96+
Time.parse(item['published_at'])
97+
}.reverse
98+
99+
File.open('db/news.yml', 'w') do |f|
100+
formatted_items = sorted_items.map do |item|
101+
{
102+
'id' => item['id'],
103+
'url' => item['url'],
104+
'title' => item['title'],
105+
'published_at' => item['published_at']
106+
}
107+
end
108+
109+
f.write({ 'news' => formatted_items }.to_yaml)
110+
end
111+
112+
logger.info("✅ Wrote #{sorted_items.size} items to db/news.yml (#{truly_new_items_sorted.size} new, #{updated_items.size} updated)")
60113
logger.info('==== END news:fetch ====')
61114
end
62115
end

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy