diff --git a/lib/tasks/fetch_news.rake b/lib/tasks/fetch_news.rake index 415d5df2..00de4927 100644 --- a/lib/tasks/fetch_news.rake +++ b/lib/tasks/fetch_news.rake @@ -7,8 +7,8 @@ require 'active_support/broadcast_logger' def safe_open(url) uri = URI.parse(url) + return File.read(url) if uri.scheme.nil? || uri.scheme == 'file' raise "不正なURLです: #{url}" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS) - Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| request = Net::HTTP::Get.new(uri) response = http.request(request) @@ -26,25 +26,19 @@ namespace :news do logger.info('==== START news:fetch ====') - # 既存の news.yml を読み込み - yaml_path = Rails.root.join('db', 'news.yml') + # YAML出力先を環境変数で上書きできるようにする + yaml_path = ENV['NEWS_YAML_PATH'] ? Pathname.new(ENV['NEWS_YAML_PATH']) : Rails.root.join('db', 'news.yml') + feed_urls = ENV['NEWS_RSS_PATH'] ? [ENV['NEWS_RSS_PATH']] : + (Rails.env.test? || Rails.env.staging? ? + [Rails.root.join('spec', 'fixtures', 'sample_news.rss').to_s] : + ['https://news.coderdojo.jp/feed/']) + existing_news = if File.exist?(yaml_path) YAML.safe_load(File.read(yaml_path), permitted_classes: [Time], aliases: true)['news'] || [] else [] end - # テスト/ステージング環境ではサンプルファイル、本番は実サイトのフィード - feed_urls = if Rails.env.test? || Rails.env.staging? - [Rails.root.join('spec', 'fixtures', 'sample_news.rss').to_s] - else - [ - 'https://news.coderdojo.jp/feed/' - # 必要に応じて他 Dojo の RSS もここに追加可能 - # 'https://coderdojotokyo.org/feed', - ] - end - # RSS 取得&パース new_items = feed_urls.flat_map do |url| logger.info("Fetching RSS → #{url}") @@ -107,7 +101,11 @@ namespace :news do Time.parse(item['published_at']) }.reverse - File.open('db/news.yml', 'w') do |f| + sorted_items.each_with_index do |item, index| + item['id'] = index + 1 + end + + File.open(yaml_path, 'w') do |f| formatted_items = sorted_items.map do |item| { 'id' => item['id'], @@ -120,7 +118,7 @@ namespace :news do f.write({ 'news' => formatted_items }.to_yaml) end - logger.info("✅ Wrote #{sorted_items.size} items to db/news.yml (#{truly_new_items_sorted.size} new, #{updated_items.size} updated)") + logger.info("✅ Wrote #{sorted_items.size} items to #{yaml_path} (#{truly_new_items_sorted.size} new, #{updated_items.size} updated)") logger.info('==== END news:fetch ====') end end diff --git a/lib/tasks/import_news.rake b/lib/tasks/import_news.rake index bebe7661..ba73110d 100644 --- a/lib/tasks/import_news.rake +++ b/lib/tasks/import_news.rake @@ -1,9 +1,10 @@ require 'yaml' namespace :news do - desc 'db/news.yml を読み込んで News テーブルを upsert する' + desc 'db/news.yml (またはENV指定のYAML)を読み込んで News テーブルを upsert する' task import_from_yaml: :environment do - yaml_path = Rails.root.join('db', 'news.yml') + # ENVで上書き可能にする(なければデフォルト db/news.yml) + yaml_path = ENV['NEWS_YAML_PATH'] ? Pathname.new(ENV['NEWS_YAML_PATH']) : Rails.root.join('db', 'news.yml') raw = YAML.safe_load(File.read(yaml_path), permitted_classes: [Time], aliases: true) # entries を計算 diff --git a/spec/models/news_spec.rb b/spec/models/news_spec.rb index 0063aaf4..45a01f29 100644 --- a/spec/models/news_spec.rb +++ b/spec/models/news_spec.rb @@ -1,5 +1,67 @@ require 'rails_helper' RSpec.describe News, type: :model do - pending "add some examples to (or delete) #{__FILE__}" + describe 'バリデーション' do + let(:news) { build(:news) } + + it '有効なファクトリーを持つ' do + expect(news).to be_valid + end + + describe 'title' do + it 'タイトルが空の場合は無効になる' do + news.title = nil + expect(news).not_to be_valid + expect(news.errors[:title]).not_to be_empty + end + end + + describe 'url' do + it 'URL が空の場合は無効になる' do + news.url = nil + expect(news).not_to be_valid + expect(news.errors[:url]).not_to be_empty + end + + it 'URL が重複している場合は無効になる' do + create(:news, url: 'https://example.com/test') + duplicate_news = build(:news, url: 'https://example.com/test') + expect(duplicate_news).not_to be_valid + expect(duplicate_news.errors[:url]).not_to be_empty + end + + it 'URL形式であること' do + news.url = 'invalid-url' + expect(news).not_to be_valid + expect(news.errors[:url]).not_to be_empty + end + + it 'HTTPSとHTTPを許可する' do + news.url = 'https://example.com' + expect(news).to be_valid + + news.url = 'http://example.com' + expect(news).to be_valid + end + end + + describe 'published_at' do + it '公開日時が空の場合は無効になる' do + news.published_at = nil + expect(news).not_to be_valid + expect(news.errors[:published_at]).not_to be_empty + end + end + end + + describe 'スコープ' do + describe '.recent' do + it '公開日時の降順で並び替える' do + old_news = create(:news, published_at: 2.days.ago) + new_news = create(:news, published_at: 1.day.ago) + + expect(News.recent).to eq([new_news, old_news]) + end + end + end end 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