11require 'rss'
2- require 'net/http'
3- require 'uri'
4- require 'yaml'
5- require 'time'
6- require 'active_support/broadcast_logger'
7-
8- def safe_open ( url )
9- uri = URI . parse ( url )
10- raise "不正なURLです: #{ url } " unless uri . is_a? ( URI ::HTTP ) || uri . is_a? ( URI ::HTTPS )
11-
12- Net ::HTTP . start ( uri . host , uri . port , use_ssl : uri . scheme == 'https' ) do |http |
13- request = Net ::HTTP ::Get . new ( uri )
14- response = http . request ( request )
15- response . body
16- end
17- end
18-
19- def fetch_rss_items ( url , logger )
20- logger . info ( "Fetching RSS → #{ url } " )
21- begin
22- rss = safe_open ( url )
23- feed = RSS ::Parser . parse ( rss , false )
24- feed . items . map { |item | item_to_hash ( item ) }
25- rescue => e
26- logger . warn ( "⚠️ Failed to fetch #{ url } : #{ e . message } " )
27- [ ]
28- end
29- end
30-
31- def item_to_hash ( item )
32- {
33- 'url' => item . link ,
34- 'title' => item . title ,
35- 'published_at' => item . pubDate . to_s
36- }
37- end
382
393namespace :news do
404 desc 'RSS フィードを取得し、db/news.yml に保存'
415 task fetch : :environment do
426 # ロガー設定(ファイル+コンソール出力)
43- file_logger = ActiveSupport ::Logger . new ( 'log/news.log' )
447 console = ActiveSupport ::Logger . new ( STDOUT )
45- logger = ActiveSupport ::BroadcastLogger . new ( file_logger , console )
8+ logger_file = ActiveSupport ::Logger . new ( 'log/news.log' )
9+ logger = ActiveSupport ::BroadcastLogger . new ( logger_file , console )
4610
4711 logger . info ( '==== START news:fetch ====' )
4812
4913 # 既存の news.yml を読み込み
50- yaml_path = Rails . root . join ( 'db' , 'news.yml' )
51- existing_news = if File . exist? ( yaml_path )
52- YAML . safe_load ( File . read ( yaml_path ) , permitted_classes : [ Time ] , aliases : true ) [ 'news' ] || [ ]
53- else
54- [ ]
55- end
14+ news_yaml_path = Rails . root . join ( 'db' , 'news.yml' )
15+ existing_news = YAML . safe_load ( File . read ( news_yaml_path ) , permitted_classes : [ Time ] , aliases : true ) [ 'news' ]
5616
5717 # テスト/ステージング環境ではサンプルファイル、本番は実サイトのフィード
58- feed_urls = if Rails . env . test? || Rails . env . staging?
59- [ Rails . root . join ( 'spec' , 'fixtures' , 'sample_news.rss' ) . to_s ]
60- else
61- [
62- 'https://news.coderdojo.jp/feed/'
63- # 必要に応じて他 Dojo の RSS もここに追加可能
64- # 'https://coderdojotokyo.org/feed',
65- ]
66- end
67-
68- new_items = feed_urls . flat_map { |url | fetch_rss_items ( url , logger ) }
18+ DOJO_NEWS_FEED = 'https://news.coderdojo.jp/feed/'
19+ RSS_FEED_LIST = Rails . env . production? ?
20+ [ DOJO_NEWS_FEED ] :
21+ [ Rails . root . join ( 'spec' , 'fixtures' , 'sample_news.rss' ) ]
22+
23+ news_items = RSS_FEED_LIST . flat_map do |feed |
24+ feed = RSS ::Parser . parse ( feed , false )
25+ feed . items . map { |item |
26+ {
27+ 'url' => item . link ,
28+ 'title' => item . title ,
29+ 'published_at' => item . pubDate . to_s
30+ }
31+ }
32+ end
6933
7034 # 既存データをハッシュに変換(URL をキーに)
7135 existing_items_hash = existing_news . index_by { |item | item [ 'url' ] }
@@ -74,7 +38,7 @@ namespace :news do
7438 truly_new_items = [ ]
7539 updated_items = [ ]
7640
77- new_items . each do |new_item |
41+ news_items . each do |new_item |
7842 if existing_items_hash . key? ( new_item [ 'url' ] )
7943 existing_item = existing_items_hash [ new_item [ 'url' ] ]
8044 # タイトルまたは公開日が変わった場合のみ更新
@@ -167,5 +131,4 @@ namespace :news do
167131 logger . info "Upserted #{ new_count + updated_count } items (#{ new_count } new, #{ updated_count } updated)."
168132 logger . info "==== END news:upsert ===="
169133 end
170-
171134end
0 commit comments