@@ -37,7 +37,7 @@ def item_to_hash(item)
3737end
3838
3939namespace :news do
40- desc 'RSS フィードから最新ニュースを取得し 、db/news.yml に書き出す '
40+ desc 'RSS フィードを取得し 、db/news.yml に保存 '
4141 task fetch : :environment do
4242 # ロガー設定(ファイル+コンソール出力)
4343 file_logger = ActiveSupport ::Logger . new ( 'log/news.log' )
@@ -73,7 +73,7 @@ namespace :news do
7373 # 新しいアイテムと既存アイテムを分離
7474 truly_new_items = [ ]
7575 updated_items = [ ]
76-
76+
7777 new_items . each do |new_item |
7878 if existing_items_hash . key? ( new_item [ 'url' ] )
7979 existing_item = existing_items_hash [ new_item [ 'url' ] ]
@@ -90,10 +90,10 @@ namespace :news do
9090 max_existing_id = existing_news . map { |item | item [ 'id' ] . to_i } . max || 0
9191
9292 # 新しいアイテムのみに ID を割り当て(古い順)
93- truly_new_items_sorted = truly_new_items . sort_by { |item |
94- Time . parse ( item [ 'published_at' ] )
93+ truly_new_items_sorted = truly_new_items . sort_by { |item |
94+ Time . parse ( item [ 'published_at' ] )
9595 }
96-
96+
9797 truly_new_items_sorted . each_with_index do |item , index |
9898 item [ 'id' ] = max_existing_id + index + 1
9999 end
@@ -106,10 +106,11 @@ namespace :news do
106106 all_items = unchanged_items + updated_items + truly_new_items_sorted
107107
108108 # 日付降順ソート
109- sorted_items = all_items . sort_by { |item |
110- Time . parse ( item [ 'published_at' ] )
109+ sorted_items = all_items . sort_by { |item |
110+ Time . parse ( item [ 'published_at' ] )
111111 } . reverse
112112
113+ # YAML ファイルに書き出し
113114 File . open ( 'db/news.yml' , 'w' ) do |f |
114115 formatted_items = sorted_items . map do |item |
115116 {
@@ -126,4 +127,45 @@ namespace :news do
126127 logger . info ( "✅ Wrote #{ sorted_items . size } items to db/news.yml (#{ truly_new_items_sorted . size } new, #{ updated_items . size } updated)" )
127128 logger . info ( '==== END news:fetch ====' )
128129 end
130+
131+ desc 'db/news.yml からデータベースに upsert'
132+ task upsert : :environment do
133+ file_logger = ActiveSupport ::Logger . new ( 'log/news.log' )
134+ console = ActiveSupport ::Logger . new ( STDOUT )
135+ logger = ActiveSupport ::BroadcastLogger . new ( file_logger , console )
136+
137+ logger . info "==== START news:upsert ===="
138+
139+ yaml_path = Rails . root . join ( 'db' , 'news.yml' )
140+ raw = YAML . safe_load ( File . read ( yaml_path ) , permitted_classes : [ Time ] , aliases : true )
141+
142+ entries = raw [ 'news' ] || [ ]
143+ new_count = 0
144+ updated_count = 0
145+
146+ News . transaction do
147+ entries . each do |attrs |
148+ news = News . find_or_initialize_by ( url : attrs [ 'url' ] )
149+ is_new = news . new_record?
150+
151+ news . assign_attributes (
152+ title : attrs [ 'title' ] ,
153+ published_at : attrs [ 'published_at' ]
154+ )
155+
156+ if is_new || news . changed?
157+ news . save!
158+ status = is_new ? 'new' : 'updated'
159+ new_count += 1 if is_new
160+ updated_count += 1 unless is_new
161+
162+ logger . info "[News] #{ news . published_at . to_date } #{ news . title } (#{ status } )"
163+ end
164+ end
165+ end
166+
167+ logger . info "Upserted #{ new_count + updated_count } items (#{ new_count } new, #{ updated_count } updated)."
168+ logger . info "==== END news:upsert ===="
169+ end
170+
129171end
0 commit comments