Skip to content

News specの強化(追加ケースの実装) #1719

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions lib/tasks/fetch_news.rake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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}")
Expand Down Expand Up @@ -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'],
Expand All @@ -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
5 changes: 3 additions & 2 deletions lib/tasks/import_news.rake
Original file line number Diff line number Diff line change
@@ -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 を計算
Expand Down
64 changes: 63 additions & 1 deletion spec/models/news_spec.rb
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +7 to +9
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有効なnewsを生成できるファクトリーがあるか?になっていると思うので、ここでは不要そうです👀
(newsモデルのバリデーションが正しく動作しているかは、以下で個別に検証しているので問題なさそうです。)


describe 'title' do
it 'タイトルが空の場合は無効になる' do
news.title = nil
expect(news).not_to be_valid
expect(news.errors[:title]).not_to be_empty
end
Comment on lines +12 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有効な場合も検証すると良さそうです!

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
Comment on lines +19 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

数が多いので、無効な場合と有効な場合で分けてあげるとわかりやすいかなと思いました💭

# 参考
  context '無効な場合' do
    it 'URL が空の場合は無効になる' do
    it 'URL が重複している場合は無効になる' do
    it 'URL形式でない場合は無効になる' do
  context '有効な場合' do
    it 'HTTPSを許可する' do
    it 'HTTPを許可する' do

また、it の説明は「どうなるか」を書いてあげると良さそうです

# 有効な場合の検証に読めてしまう
-  it 'URL形式であること' do

# it の説明は「~なる」「〜する」など動詞がわかりやすいと教えてもらいました📝
+  it 'URL形式でない場合は無効になる' do


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
Comment on lines +48 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここも有効な場合も検証すると良さそうです🛠️

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