feat: 類似度算出バッチ修正,ほか(#228) (#232)

#228

#228

#228

Co-authored-by: miteruzo <miteruzo@naver.com>
Reviewed-on: #232
This commit was merged in pull request #232.
This commit is contained in:
2026-01-22 23:30:08 +09:00
parent 86209dcc84
commit f6de272f55
18 changed files with 553 additions and 76 deletions
+134
View File
@@ -0,0 +1,134 @@
# spec/requests/tag_children_spec.rb
require "rails_helper"
RSpec.describe "TagChildren", type: :request do
let!(:parent) { create(:tag) }
let!(:child) { create(:tag) }
# ここは君のUser factoryに合わせて調整
let(:user) { create_member_user! }
let(:admin) { create_admin_user! }
# current_user を ApplicationController でスタブ
def stub_current_user(user_or_nil)
allow_any_instance_of(ApplicationController)
.to receive(:current_user)
.and_return(user_or_nil)
end
describe "POST /tag_children" do
subject(:do_request) do
post "/tags/#{ parent_id }/children/#{ child_id }"
end
context "when not logged in" do
let(:parent_id) { parent.id }
let(:child_id) { child.id }
it "returns 401" do
stub_current_user(nil)
do_request
expect(response).to have_http_status(:unauthorized)
end
end
context "when logged in but not admin" do
let(:parent_id) { parent.id }
let(:child_id) { child.id }
it "returns 403" do
stub_current_user(user)
do_request
expect(response).to have_http_status(:forbidden)
end
end
context "when admin and params are present" do
before { stub_current_user(admin) }
let(:parent_id) { parent.id }
let(:child_id) { child.id }
it "returns 204 and adds child to parent.children" do
expect(parent.children).not_to include(child)
expect { do_request }
.to change { parent.reload.children.ids.include?(child.id) }
.from(false).to(true)
expect(response).to have_http_status(:no_content)
end
end
context "when Tag.find raises (invalid ids) it still returns 204" do
before { stub_current_user(admin) }
let(:parent_id) { -1 }
let(:child_id) { -1 }
it "returns 204 (rescue nil)" do
do_request
expect(response).to have_http_status(:no_content)
end
end
end
describe "DELETE /tag_children" do
subject(:do_request) do
delete "/tags/#{ parent_id }/children/#{ child_id }"
end
context "when not logged in" do
let(:parent_id) { parent.id }
let(:child_id) { child.id }
it "returns 401" do
stub_current_user(nil)
do_request
expect(response).to have_http_status(:unauthorized)
end
end
context "when logged in but not admin" do
let(:parent_id) { parent.id }
let(:child_id) { child.id }
it "returns 403" do
stub_current_user(user)
do_request
expect(response).to have_http_status(:forbidden)
end
end
context "when admin and params are present" do
before do
stub_current_user(admin)
parent.children << child
end
let(:parent_id) { parent.id }
let(:child_id) { child.id }
it "returns 204 and removes child from parent.children" do
expect(parent.reload.children).to include(child)
expect { do_request }
.to change { parent.reload.children.ids.include?(child.id) }
.from(true).to(false)
expect(response).to have_http_status(:no_content)
end
end
context "when Tag.find raises (invalid ids) it still returns 204" do
before { stub_current_user(admin) }
let(:parent_id) { -1 }
let(:child_id) { -1 }
it "returns 204 (rescue nil)" do
do_request
expect(response).to have_http_status(:no_content)
end
end
end
end
+99
View File
@@ -76,4 +76,103 @@ RSpec.describe 'Tags API', type: :request do
expect(response).to have_http_status(:not_found)
end
end
# member? を持つ user を想定(Factory 側で trait 作ってもOK
let(:member_user) { create(:user) }
let(:non_member_user) { create(:user) }
def stub_current_user(user)
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user)
end
before do
allow(member_user).to receive(:member?).and_return(true)
allow(non_member_user).to receive(:member?).and_return(false)
end
describe "PATCH /tags/:id" do
context "未ログイン" do
before { stub_current_user(nil) }
it "401 を返す" do
patch "/tags/#{tag.id}", params: { name: "new" }
expect(response).to have_http_status(:unauthorized)
end
end
context "ログインしてゐるが member でない" do
before { stub_current_user(non_member_user) }
it "403 を返す" do
patch "/tags/#{tag.id}", params: { name: "new" }
expect(response).to have_http_status(:forbidden)
end
end
context "member" do
before { stub_current_user(member_user) }
it "name だけ更新できる" do
patch "/tags/#{tag.id}", params: { name: "new" }
expect(response).to have_http_status(:ok)
tag.reload
expect(tag.name).to eq("new")
expect(tag.category).to eq("general")
json = JSON.parse(response.body)
expect(json["id"]).to eq(tag.id)
expect(json["name"]).to eq("new")
expect(json["category"]).to eq("general")
end
it "category だけ更新できる" do
patch "/tags/#{tag.id}", params: { category: "meme" }
expect(response).to have_http_status(:ok)
tag.reload
expect(tag.name).to eq("spec_tag")
expect(tag.category).to eq("meme")
end
it "空文字は presence により無視され、更新は走らない(値が変わらない)" do
patch "/tags/#{tag.id}", params: { name: "", category: " " }
expect(response).to have_http_status(:ok)
tag.reload
expect(tag.name).to eq("spec_tag")
expect(tag.category).to eq("general")
end
it "両方更新できる" do
patch "/tags/#{tag.id}", params: { name: "n", category: "meta" }
expect(response).to have_http_status(:ok)
tag.reload
expect(tag.name).to eq("n")
expect(tag.category).to eq("meta")
end
it "存在しない id だと RecordNotFound になる(通常は 404" do
# Rails 設定次第で例外がそのまま上がる/404になる
# APIなら rescue_from で 404 にしてることが多いので、その場合は 404 を期待。
patch "/tags/999999999", params: { name: "x" }
expect(response.status).to be_in([404, 500])
end
it "バリデーションで update! が失敗したら(通常は 422 か 500)" do
patch "/tags/#{tag.id}", params: { name: 'new', category: 'nico' }
# rescue_from の実装次第で変はる:
# - RecordInvalid を 422 にしてるなら 422
# - 未処理なら 500
expect(response.status).to be_in([422, 500])
end
end
end
end