Skip to content

Conversation

@cloudwi
Copy link
Owner

@cloudwi cloudwi commented Dec 19, 2025

…ntials

API Changes:

  • Change POST /places/:id/like to POST /places/:place_id/likes for better REST semantics
  • Split PlacesController to separate concerns (PlacesController + PlaceLikesController)
  • Allow users to like any place, not just their own places
  • Remove authentication from external search endpoint for public access

Code Quality Improvements:

  • Migrate from .env to Rails credentials for secure configuration management
  • Add SQL injection protection to search queries with sanitize_sql_like
  • Remove obsolete Folder model association from User model
  • Update Swagger documentation to reflect new API structure

Testing:

  • Create comprehensive RSpec test suite with 24 examples
  • Add test environment credentials for proper JWT authentication in tests
  • Fix nullable field schemas in Swagger specs
  • All tests passing (26 examples, 0 failures)
  • Rubocop lint checks passing

Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • 장소 좋아요 기능 추가 (좋아요/취소 토글)
    • 외부 검색이 로그인 없이 이용 가능하도록 변경
  • 변경 사항

    • 경로 안내 기능 제거
    • 내 검색에서 코스 검색 기능 제거 (장소 검색만 제공)
    • API 엔드포인트 및 응답 구조 업데이트

✏️ Tip: You can customize this high-level summary in your review settings.

…ntials

API Changes:
- Change POST /places/:id/like to POST /places/:place_id/likes for better REST semantics
- Split PlacesController to separate concerns (PlacesController + PlaceLikesController)
- Allow users to like any place, not just their own places
- Remove authentication from external search endpoint for public access

Code Quality Improvements:
- Migrate from .env to Rails credentials for secure configuration management
- Add SQL injection protection to search queries with sanitize_sql_like
- Remove obsolete Folder model association from User model
- Update Swagger documentation to reflect new API structure

Testing:
- Create comprehensive RSpec test suite with 24 examples
- Add test environment credentials for proper JWT authentication in tests
- Fix nullable field schemas in Swagger specs
- All tests passing (26 examples, 0 failures)
- Rubocop lint checks passing
@coderabbitai
Copy link

coderabbitai bot commented Dec 19, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

경로 탐색(방향 찾기) 기능을 완전히 제거하고, 장소 기반 API로 재설계된 변경사항입니다. 기존 DirectionsController와 관련 서비스(OdsayTransitService, NaverDirectionsService)를 삭제하고, 장소 좋아요 기능을 새로운 컨트롤러로 분리했으며, /api/v1/my_search 엔드포인트를 장소 검색 전용으로 단순화했습니다.

Changes

Cohort / File(s) 설명
경로 탐색 기능 제거
app/controllers/api/v1/courses_controller.rb, app/controllers/api/v1/directions_controller.rb
CoursesController에서 directions 메서드 제거; DirectionsController 전체 삭제
경로 탐색 서비스 제거
app/services/odsay_transit_service.rb, app/services/naver_directions_service.rb
교통/운전 경로 검색 서비스 클래스 전체 삭제
장소 좋아요 리팩토링
app/controllers/api/v1/places_controller.rb, app/controllers/api/v1/place_likes_controller.rb
PlacesController에서 like 메서드 제거; 토글 좋아요 기능을 새 PlaceLikesController로 이동
API 검색 엔드포인트 개선
app/controllers/api/v1/my_search_controller.rb, app/controllers/api/v1/external_controller.rb
MySearchController를 장소만 반환하도록 단순화; ExternalController에서 로그인 요구사항 제거
서비스 레이어 업데이트
app/services/naver_search_service.rb
지오코딩 폴백 경로 제거, 자격증명 접근 방식 단순화, 로깅 추가
라우팅 및 설정 변경
config/routes.rb, config/database.yml
경로 기반 directions 멤버 라우트 제거; 새 /places/:id/likes 중첩 리소스 추가; 데이터베이스 자격증명 조회 방식 업데이트
사용자 모델 수정
app/models/user.rb
has_many :folders, dependent: :destroy 연관관계 제거
암호화된 자격증명 파일
config/credentials/development.yml.enc, config/credentials/test.yml.enc
새 암호화된 자격증명 파일 추가
API 문서 업데이트
swagger/v1/swagger.yaml
경로 탐색 엔드포인트 제거; 외부/내부 검색, 장소 목록, 좋아요 토글 엔드포인트 추가/갱신
테스트 스펙 전면 개편
spec/requests/api/v1/courses_spec.rb, test/controllers/api/v1/directions_controller_test.rb, spec/requests/api/v1/my_search_spec.rb, spec/requests/api/v1/places_spec.rb, spec/requests/api/v1/popular_places_spec.rb
경로 탐색 테스트 완전 제거; 새 장소 관련 엔드포인트에 대한 rswag 스펙 추가

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title partially describes a key change (refactoring API design with RESTful conventions and Rails credentials) but is truncated at 70 characters and lacks specificity about the main modifications. Complete the title to clearly convey primary changes, such as: 'Refactor: Improve API design with RESTful conventions and migrate to Rails credentials' or be more specific about the scope of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c7f17f and a7ebe2b.

📒 Files selected for processing (3)
  • app/controllers/api/v1/my_search_controller.rb
  • config/database.yml
  • spec/requests/api/v1/courses_spec.rb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/controllers/api/v1/my_search_controller.rb (1)

69-69: Add index on likes_count for ORDER BY performance.

The code orders by likes_count descending, which requires a database index for efficient query performance as the dataset grows. Add an index on likes_count or a composite index on (likes_count, created_at) to avoid full table scans.

🧹 Nitpick comments (2)
app/controllers/api/v1/external_controller.rb (1)

6-45: Consider rate limiting for the public search endpoint.

Making the external search endpoint public aligns with the PR objectives. However, public APIs are susceptible to abuse and excessive usage. Consider implementing rate limiting (e.g., using rack-attack gem) to protect against:

  • Excessive requests from individual IPs
  • Potential cost implications from proxying Naver API calls
  • Service degradation from abuse
Example rate limiting configuration

If you add rack-attack to your Gemfile, you could configure something like:

# config/initializers/rack_attack.rb
Rack::Attack.throttle("external_search/ip", limit: 30, period: 1.minute) do |req|
  req.ip if req.path == "/api/v1/external/search"
end
app/controllers/api/v1/my_search_controller.rb (1)

83-85: Consider using Rails' built-in ActiveRecord::Base.sanitize_sql_like.

Rails provides a built-in sanitize_sql_like method in ActiveRecord::Base that handles LIKE pattern escaping. Using the framework's method is preferable for maintainability and consistency.

🔎 Proposed refactor
-  def sanitize_sql_like(string)
-    string.gsub(/[\\%_]/) { |m| "\\#{m}" }
-  end
+  def sanitize_sql_like(string)
+    ActiveRecord::Base.sanitize_sql_like(string)
+  end

Or simply call ActiveRecord::Base.sanitize_sql_like(query) directly at each usage site and remove this helper method entirely.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed463d3 and 7c7f17f.

📒 Files selected for processing (22)
  • app/controllers/api/v1/courses_controller.rb (0 hunks)
  • app/controllers/api/v1/directions_controller.rb (0 hunks)
  • app/controllers/api/v1/external_controller.rb (1 hunks)
  • app/controllers/api/v1/my_search_controller.rb (2 hunks)
  • app/controllers/api/v1/place_likes_controller.rb (1 hunks)
  • app/controllers/api/v1/places_controller.rb (1 hunks)
  • app/models/user.rb (0 hunks)
  • app/services/naver_directions_service.rb (0 hunks)
  • app/services/naver_search_service.rb (3 hunks)
  • app/services/odsay_transit_service.rb (0 hunks)
  • config/credentials/development.yml.enc (1 hunks)
  • config/credentials/test.yml.enc (1 hunks)
  • config/database.yml (1 hunks)
  • config/initializers/omniauth.rb (1 hunks)
  • config/routes.rb (1 hunks)
  • spec/requests/api/v1/courses_spec.rb (0 hunks)
  • spec/requests/api/v1/directions_spec.rb (0 hunks)
  • spec/requests/api/v1/my_search_spec.rb (1 hunks)
  • spec/requests/api/v1/places_spec.rb (1 hunks)
  • spec/requests/api/v1/popular_places_spec.rb (1 hunks)
  • swagger/v1/swagger.yaml (1 hunks)
  • test/controllers/api/v1/directions_controller_test.rb (0 hunks)
💤 Files with no reviewable changes (8)
  • app/models/user.rb
  • spec/requests/api/v1/courses_spec.rb
  • app/controllers/api/v1/courses_controller.rb
  • app/services/naver_directions_service.rb
  • test/controllers/api/v1/directions_controller_test.rb
  • app/services/odsay_transit_service.rb
  • app/controllers/api/v1/directions_controller.rb
  • spec/requests/api/v1/directions_spec.rb
🧰 Additional context used
🧬 Code graph analysis (3)
app/controllers/api/v1/place_likes_controller.rb (2)
app/controllers/api/v1/places_controller.rb (2)
  • before_action (3-57)
  • set_place (33-37)
app/controllers/application_controller.rb (1)
  • current_user (36-38)
app/controllers/api/v1/places_controller.rb (1)
app/controllers/api/v1/place_likes_controller.rb (1)
  • before_action (3-38)
spec/requests/api/v1/places_spec.rb (1)
app/services/json_web_token.rb (1)
  • encode (4-7)
🔇 Additional comments (17)
app/services/naver_search_service.rb (3)

20-36: LGTM: Consistent credential pattern for local search.

The credential access pattern change aligns with the broader migration to Rails credentials. The safe navigation operator properly handles missing credentials.


38-55: Fix API endpoint for Naver Cloud Platform Geocoding API.

The endpoint is incorrect: code uses maps.apigw.ntruss.com but official NCP documentation specifies https://naveropenapi.apigw.ntruss.com/map-geocode/v2. This will cause authentication or routing failures. Additionally, verify that credentials changed from naver_cloud to naver are compatible with NCP's Geocoding service, as separate credentials may be required for Naver Cloud Platform Maps versus Naver Developers API.


10-17: Verify intentional API contract change: search_places no longer attempts geocoding fallback.

The method now only returns local search results and returns an empty array on error, removing the fallback to address geocoding that may have existed previously. The separate search_address method still provides geocoding functionality.

Confirm with the team that clients relying on search_places for address-based searches won't be impacted. The public API endpoint in ExternalController will now only return local place results, not geocoding results.

spec/requests/api/v1/popular_places_spec.rb (1)

1-44: LGTM: Well-structured API specification test.

The test properly documents the Popular Places endpoint with:

  • Comprehensive response schema including all place fields
  • Type definitions and descriptions for each property
  • Required fields specification
  • Integration with Swagger documentation
app/controllers/api/v1/places_controller.rb (1)

5-5: LGTM: Correct RESTful refactoring of like functionality.

The removal of the like action and its corresponding before_action filter correctly implements the separation of concerns. The like functionality moved to PlaceLikesController (visible in the related snippets), which:

  • Uses Place.find(params[:place_id]) instead of current_user.places.find
  • Allows users to like any place, not just their own
  • Follows RESTful conventions with POST /api/v1/places/:place_id/likes

The set_place method's restriction to current_user.places remains appropriate for the show action in this controller.

config/initializers/omniauth.rb (1)

11-14: Environment-specific credentials are properly supported in Rails 8.1.1.

The credential access pattern using safe navigation (Rails.application.credentials.kakao&.client_id) is correct. Rails 6 added support for multi-environment credentials with separate files and encryption keys, and Rails 8.1.1 fully supports this feature.

Verify that credentials files exist with the correct structure:

  • config/credentials/development.yml.enc (or environment-specific file for current environment)
  • config/credentials/production.yml.enc (for production)
  • Each file contains a top-level kakao key with nested client_id and client_secret

The safe navigation operator usage is appropriate for handling nil-safe access to nested credential keys.

app/controllers/api/v1/my_search_controller.rb (1)

58-58: Good SQL injection protection implementation.

The sanitization is correctly applied before string interpolation in LIKE patterns, and the .present? guards ensure nil values won't reach the sanitization method.

Also applies to: 62-67, 77-77

app/controllers/api/v1/place_likes_controller.rb (3)

9-29: LGTM! Clean toggle implementation.

The like/unlike toggle logic is clear and correctly handles both adding and removing likes. Using bang methods (destroy!, create!) ensures failures raise exceptions that will be caught by the default error handler.


33-37: Design change allows liking any place (not just own places).

This implementation allows users to like any place in the system, not just their own. This differs from PlacesController#set_place (which scopes to current_user.places) and aligns with the PR objective: "Allow users to like any place (no longer restricted to their own places)."


17-17: The counter_cache: :likes_count configuration is correctly set up.

The reload calls are necessary to refresh the in-memory object after creating or destroying place likes. Since Rails automatically updates the database via counter_cache, reload ensures the response reflects the updated count.

Also applies to: 25-25

spec/requests/api/v1/places_spec.rb (2)

1-170: Comprehensive test coverage for Places API.

The test suite provides excellent coverage of success and error scenarios (200, 401, 404) for all Places API endpoints. The schema definitions are detailed and include proper nullable field annotations.


102-110: Good practice: Explicit nullable field annotations.

The schema properly marks optional fields as nullable: true, which improves API documentation accuracy and helps consumers understand which fields may be absent.

spec/requests/api/v1/my_search_spec.rb (1)

1-96: Well-structured test specifications for search endpoints.

The tests provide clear documentation of the search API parameters and response schemas. The enum specification for the type parameter is particularly helpful for API consumers.

config/routes.rb (1)

39-44: Excellent RESTful design for nested likes resource.

Using a nested singular resource for likes (POST /places/:place_id/likes) properly represents the relationship and follows REST conventions. The route structure is intuitive and self-documenting.

swagger/v1/swagger.yaml (3)

592-627: Accurate documentation for likes toggle endpoint.

The Swagger definition correctly documents the RESTful like toggle endpoint with appropriate parameter naming (place_id), response schema, and security requirements.


554-587: Consistent nullable field annotations across documentation.

The Swagger schema properly marks optional fields as nullable: true, consistent with the RSpec specifications. This attention to detail improves API documentation quality.


189-270: Verify external search endpoint authentication requirement.

The Swagger documentation correctly indicates this endpoint is public (no security declaration), and this aligns with the implementation. The Api::V1::ExternalController#search action does not declare before_action :require_login. The base ApplicationController applies an optional authenticate_request filter that only attempts JWT verification if an Authorization header is present; unauthenticated requests are allowed.

cloudwi and others added 2 commits December 24, 2025 09:38
Remove course-related search capabilities from my_search controller. Update SQL sanitization to use ActiveRecord::Base.sanitize_sql_like. Remove courses_spec file as course functionality has been removed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Resolve conflicts by accepting improved credentials access pattern and removing course-related functionality.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@cloudwi cloudwi merged commit 0ea84c2 into main Dec 24, 2025
3 of 4 checks passed
@cloudwi cloudwi deleted the refactor/restful-api-improvements branch December 24, 2025 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants