Skip to content

Commit

Permalink
Merge pull request #115 from Progaku-copy/feature/#114-add-tags-to-me…
Browse files Browse the repository at this point in the history
…mo-response

メモ一覧・詳細APIのレスポンスにタグ名を追加
  • Loading branch information
kakeru-one authored Oct 19, 2024
2 parents 1d6d9fb + fbd6ab4 commit fc7da68
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 29 deletions.
6 changes: 6 additions & 0 deletions backend/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ gem 'rails-i18n' # i18n 日本語化対応用gem
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
gem "rack-cors"

# bulk upsertを実現する
# Github: https://github.com/zdennis/activerecord-import
gem 'activerecord-import'

group :development, :test do
# Github: https://github.com/willnet/committee-rails
gem 'committee-rails'
Expand Down Expand Up @@ -86,4 +90,6 @@ group :test do

# Github: https://github.com/simplecov-ruby/simplecov
gem 'simplecov', require: false # テストカバレッジを取得するためのgem

gem "test-prof", "~> 1.4"
end
7 changes: 6 additions & 1 deletion backend/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ GEM
activemodel (= 7.2.1)
activesupport (= 7.2.1)
timeout (>= 0.4.0)
activerecord-import (1.8.1)
activerecord (>= 4.2)
activestorage (7.2.1)
actionpack (= 7.2.1)
activejob (= 7.2.1)
Expand Down Expand Up @@ -101,9 +103,9 @@ GEM
reline (>= 0.3.1)
diff-lcs (1.5.0)
diffy (3.4.2)
docile (1.4.1)
drb (2.2.1)
erubi (1.13.0)
docile (1.4.1)
factory_bot (6.2.1)
activesupport (>= 5.0.0)
factory_bot_rails (6.2.0)
Expand Down Expand Up @@ -280,6 +282,7 @@ GEM
simplecov-html (0.13.1)
simplecov_json_formatter (0.1.4)
stringio (3.0.8)
test-prof (1.4.2)
thor (1.3.2)
timeout (0.4.1)
tzinfo (2.0.6)
Expand All @@ -297,6 +300,7 @@ PLATFORMS
x86_64-linux

DEPENDENCIES
activerecord-import
annotate
bcrypt (~> 3.1.7)
bootsnap
Expand All @@ -319,6 +323,7 @@ DEPENDENCIES
rubocop-rails
rubocop-rspec
simplecov
test-prof (~> 1.4)
tzinfo-data

RUBY VERSION
Expand Down
11 changes: 7 additions & 4 deletions backend/app/controllers/memos_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
class MemosController < ApplicationController
# GET /memos
def index
render json: Memo::Query.call(filter_collection: Memo.all, params: params), status: :ok
@memos = \
Memo::Query.call(
filter_collection: Memo.preload(:tags),
params: params
)
rescue TypeError
render json: { error: 'ページパラメータが無効です' }, status: :bad_request
end

# GET /memos/:id
def show
@memo = Memo.find(params[:id])
@comments = @memo.comments.order(id: 'DESC')
render 'show', status: :ok
@memo = Memo.preload(:tags).find(params[:id])
@comments = @memo.comments.order(id: :desc)
end

# POST /memos
Expand Down
12 changes: 12 additions & 0 deletions backend/app/views/memos/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

json.memos @memos[:memos] do |memo|
json.id memo.id
json.title memo.title
json.content memo.content
json.poster memo.poster
json.created_at memo.created_at
json.updated_at memo.updated_at
json.tag_names memo.tags.map(&:name)
end
json.total_page @memos[:total_page]
2 changes: 2 additions & 0 deletions backend/app/views/memos/show.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ json.memo do
json.created_at @memo.created_at
json.updated_at @memo.updated_at

json.tag_names @memo.tags.map(&:name)

json.comments @comments do |comment|
json.id comment.id
json.content comment.content
Expand Down
7 changes: 7 additions & 0 deletions backend/doc/components/memoSchema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ components:
type: string
format: date-time
example: 2021-01-01T00:00:00.000Z
tag_names:
type: array
items:
type: string
example:
- タグ1
- タグ2
comments:
type: array
items:
Expand Down
7 changes: 1 addition & 6 deletions backend/doc/paths/memo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,10 @@ paths:
type: array
items:
$ref: '../components/memoSchema.yml#/components/schemas/memo'
total_count:
type: integer
example: 1
total_pages:
type: integer
example: 1
current_page:
type: integer
example: 1

'400':
description: Bad Request
content:
Expand Down
6 changes: 6 additions & 0 deletions backend/spec/factories/memos.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,11 @@
title { Faker::Lorem.sentence(word_count: 3) }
content { Faker::Lorem.paragraph(sentence_count: 5) }
poster { Faker::Name.name }

trait :with_tags do
after :create do |memo|
create_list(:memo_tag, 3, memo: memo)
end
end
end
end
41 changes: 26 additions & 15 deletions backend/spec/models/memo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,62 +110,73 @@

describe 'Query::call(filter_collection:, params:)' do
let(:memos) do
{
'1' => create(:memo, title: 'テスト タイトル1', content: 'テスト コンテンツ1'),
'2' => create(:memo, title: 'テスト タイトル2', content: 'テスト コンテンツ2'),
'3' => create(:memo, title: 'その他 タイトル', content: 'その他 コンテンツ')
}
[
create(:memo, title: 'テスト タイトル1', content: 'テスト コンテンツ1'),
create(:memo, title: 'テスト タイトル2', content: 'テスト コンテンツ2'),
create(:memo, title: 'その他 タイトル', content: 'その他 コンテンツ')
]
end

context 'タイトルで検索した場合' do
it 'タイトルフィルターが正しく機能し、期待されるメモが取得できることを確認する' do
aggregate_failures do
result = Memo::Query.call(filter_collection: described_class.all, params: { title: 'テスト' })
expect(result[:memos]).to include(memos['1'], memos['2'])
expect(result[:memos]).not_to include(memos['3'])
expect(result[:memos]).to include(memos[0], memos[1])
end
end
end

context 'コンテンツで検索した場合' do
it 'コンテンツフィルターが正しく機能し、期待されるメモが取得できることを確認する' do
result = Memo::Query.call(filter_collection: described_class.all, params: { content: 'コンテンツ' })
expect(result[:memos]).to include(memos['1'], memos['2'], memos['3'])
expect(result[:memos]).to include(memos[0], memos[1], memos[2])
end
end

context 'タイトルとコンテンツで検索した場合' do
it 'タイトルとコンテンツの両方でフィルターが正しく機能し、期待されるメモが取得できることを確認する' do
aggregate_failures do
result = Memo::Query.call(filter_collection: described_class.all, params: { title: 'その他', content: 'コンテンツ' })
expect(result[:memos]).to include(memos['3'])
expect(result[:memos]).not_to include(memos['1'], memos['2'])
expect(result[:memos]).to include(memos[2])
expect(result[:memos]).not_to include(memos[0], memos[1])
end
end
end

context '並び替え機能のテスト' do
it '昇順機能が正しく機能していること' do
result = Memo::Query.call(filter_collection: described_class.all, params: { order: 'asc' })
expect(result[:memos]).to contain_exactly(memos['1'], memos['2'], memos['3'])
expect(result[:memos]).to contain_exactly(memos[0], memos[1], memos[2])
end

it 'デフォルトで降順機能が正しく機能されていること' do
aggregate_failures do
result = Memo::Query.call(filter_collection: described_class.all, params: {})
expect(result[:memos]).to contain_exactly(memos['3'], memos['2'], memos['1'])
expect(result[:memos]).to contain_exactly(memos[2], memos[1], memos[0])
end
end
end

context 'ページネーション機能のテスト' do
before { create_list(:memo, 20) }
before do
memos_data = Array.new(20) do
{
title: Faker::Lorem.sentence(word_count: 3),
content: Faker::Lorem.paragraph(sentence_count: 5),
poster: Faker::Name.name,
created_at: Time.current,
updated_at: Time.current
}
end

described_class.bulk_import!(memos_data)
end

it '指定したページ数のメモ、総数、ページ数、ページ番号が取得できること' do
it '指定したページ数のメモ、総数が取得できること' do
aggregate_failures do
result = Memo::Query.call(filter_collection: described_class.all, params: { page: 2 })
memo_relation = described_class.order(id: :desc).limit(10).offset(10)
expect(result[:memos].pluck(:id)).to eq(memo_relation.pluck(:id))
expect(result[:memos].pluck('id')).to eq(memo_relation.pluck(:id))
expect(result[:total_page]).to eq(2)
end
end
Expand Down
4 changes: 4 additions & 0 deletions backend/spec/rails_helper.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'simplecov'
# ref: https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md
require 'test_prof/recipes/rspec/let_it_be'
# ref: https://github.com/test-prof/test-prof/blob/master/docs/recipes/before_all.md
require 'test_prof/recipes/rspec/before_all'

SimpleCov.start 'rails' do
add_filter '/app/channels/'
Expand Down
56 changes: 53 additions & 3 deletions backend/spec/requests/memos_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,67 @@
let!(:user) { create(:user) }

describe 'GET /memos' do
let!(:memos) { create_list(:memo, 20) }
# そこそこ重いSQLを発行するので、一回だけ呼ばれるようにしたい。
# ref: https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md
let_it_be(:memos) do
memos_data = Array.new(20) do
{
title: Faker::Lorem.sentence(word_count: 3),
content: Faker::Lorem.paragraph(sentence_count: 5),
poster: Faker::Name.name,
created_at: Time.current,
updated_at: Time.current
}
end

Memo.bulk_import!(memos_data)
Memo.order(:id).last(20)
end

# そこそこ重いSQLを発行するので、一回だけ呼ばれるようにしたい。
# ref: https://github.com/test-prof/test-prof/blob/master/docs/recipes/before_all.md
before_all do
# Tagの生成
tag_data = Array.new(3) do |n|
{
name: "tag-#{n + 1}",
priority: n + 1,
created_at: Time.current,
updated_at: Time.current
}
end
Tag.bulk_import!(tag_data)
tags = Tag.pluck(:id)

# MemoTagの生成
memo_tags_data = memos.flat_map do |memo|
tags.map do |tag_id|
{
memo_id: memo.id,
tag_id: tag_id,
created_at: Time.current,
updated_at: Time.current
}
end
end
MemoTag.bulk_import!(memo_tags_data)
end

context 'ログイン中かつメモが存在し、パラメータが指定されていない場合' do
before { sign_in(user) }

it '降順で、1ページ目に10件のメモが返ること' do
aggregate_failures do
get '/memos'
get '/memos', headers: { Accept: 'application/json' }
assert_request_schema_confirm
assert_response_schema_confirm(200)
expect(response.parsed_body['memos'].length).to eq(10)
result_memo_ids = response.parsed_body['memos'].map { _1['id'] } # rubocop:disable Rails/Pluck
expected_memo_ids = memos.reverse.map(&:id)
result_memo_tags = response.parsed_body['memos'].map { _1['tag_names'] } # rubocop:disable Rails/Pluck
expected_memo_tags = memos.reverse.map { |memo| memo.tags.map(&:name) }
expect(result_memo_ids).to eq(expected_memo_ids[0..9])
expect(result_memo_tags).to eq(expected_memo_tags[0..9])
expect(response.parsed_body['total_page']).to eq(2)
end
end
Expand All @@ -28,13 +75,16 @@

it '降順で、指定されたページに10件のメモが返ること' do
aggregate_failures do
get '/memos', params: { page: 2 }
get '/memos', params: { page: 2 }, headers: { Accept: 'application/json' }
assert_request_schema_confirm
assert_response_schema_confirm(200)
expect(response.parsed_body['memos'].length).to eq(10)
result_memo_ids = response.parsed_body['memos'].pluck('id')
expected_memo_ids = memos.sort_by(&:id).reverse[10..19].map(&:id)
result_memo_tags = response.parsed_body['memos'].map { _1['tag_names'] } # rubocop:disable Rails/Pluck
expected_memo_tags = memos.reverse.map { |memo| memo.tags.map(&:name) }
expect(result_memo_ids).to eq(expected_memo_ids)
expect(result_memo_tags).to eq(expected_memo_tags[10..19])
expect(response.parsed_body['total_page']).to eq(2)
end
end
Expand Down

0 comments on commit fc7da68

Please sign in to comment.