Files
thrillwiki_django_no_react/docs/ride-get-by-slug-fix-documentation.md
pacnpal c2c26cfd1d Add comprehensive API documentation for ThrillWiki integration and features
- Introduced Next.js integration guide for ThrillWiki API, detailing authentication, core domain APIs, data structures, and implementation patterns.
- Documented the migration to Rich Choice Objects, highlighting changes for frontend developers and enhanced metadata availability.
- Fixed the missing `get_by_slug` method in the Ride model, ensuring proper functionality of ride detail endpoints.
- Created a test script to verify manufacturer syncing with ride models, ensuring data integrity across related models.
2025-09-16 11:29:17 -04:00

5.2 KiB

Ride get_by_slug Method Implementation Fix

Date: September 15, 2025
Issue: AttributeError: type object 'Ride' has no attribute 'get_by_slug'
Status: RESOLVED

Problem Description

The API endpoint /api/v1/parks/{park_slug}/rides/{ride_slug}/ was failing with an AttributeError because the Ride model was missing the get_by_slug class method that was being called in the ParkRideDetailAPIView.

Error Details

{"status":"error","error":{"code":"ATTRIBUTEERROR","message":"type object 'Ride' has no attribute 'get_by_slug'","details":null,"request_user":"AnonymousUser"},"data":null}

Root Cause

The ParkRideDetailAPIView in backend/apps/api/v1/parks/park_rides_views.py was calling:

ride, is_historical = Ride.get_by_slug(ride_slug, park=park)

However, the Ride model in backend/apps/rides/models/rides.py did not have this method implemented, while the Park model did have this pattern implemented.

Solution Implemented

1. Added get_by_slug Class Method to Ride Model

Added the following method to the Ride class in backend/apps/rides/models/rides.py:

@classmethod
def get_by_slug(cls, slug: str, park=None) -> tuple["Ride", bool]:
    """Get ride by current or historical slug, optionally within a specific park"""
    from django.contrib.contenttypes.models import ContentType
    from apps.core.history import HistoricalSlug

    # Build base query
    base_query = cls.objects
    if park:
        base_query = base_query.filter(park=park)

    try:
        ride = base_query.get(slug=slug)
        return ride, False
    except cls.DoesNotExist:
        # Try historical slugs in HistoricalSlug model
        content_type = ContentType.objects.get_for_model(cls)
        historical_query = HistoricalSlug.objects.filter(
            content_type=content_type, slug=slug
        ).order_by("-created_at")

        for historical in historical_query:
            try:
                ride = base_query.get(pk=historical.object_id)
                return ride, True
            except cls.DoesNotExist:
                continue

        # Try pghistory events
        event_model = getattr(cls, "event_model", None)
        if event_model:
            historical_events = event_model.objects.filter(slug=slug).order_by("-pgh_created_at")
            
            for historical_event in historical_events:
                try:
                    ride = base_query.get(pk=historical_event.pgh_obj_id)
                    return ride, True
                except cls.DoesNotExist:
                    continue

        raise cls.DoesNotExist("No ride found with this slug")

2. Method Features

The implemented method provides:

  • Current slug lookup: First attempts to find the ride by its current slug
  • Historical slug support: Falls back to checking historical slugs in the HistoricalSlug model
  • pghistory integration: Also checks pghistory events for historical slug changes
  • Park filtering: Optional park parameter to limit search to rides within a specific park
  • Return tuple: Returns (ride_instance, is_historical) where is_historical indicates if the slug was found in historical records

3. Pattern Consistency

This implementation follows the same pattern as the existing Park.get_by_slug() method, ensuring consistency across the codebase.

Testing Results

Before Fix

curl -n "http://localhost:8000/api/v1/parks/busch-gardens-tampa/rides/valkyrie/"

Result: AttributeError

After Fix

curl -n "http://localhost:8000/api/v1/parks/busch-gardens-tampa/rides/valkyrie/"

Result: Success - Returns complete ride data:

{
  "id": 613,
  "name": "Valkyrie",
  "slug": "valkyrie",
  "category": "FR",
  "status": "OPERATING",
  "description": "Exciting FR ride with thrilling elements and smooth operation",
  "park": {
    "id": 252,
    "name": "Busch Gardens Tampa",
    "slug": "busch-gardens-tampa",
    "url": "http://www.thrillwiki.com/parks/busch-gardens-tampa/"
  },
  "park_area": {
    "id": 794,
    "name": "Fantasyland",
    "slug": "fantasyland"
  },
  // ... additional ride data
}

Impact

Fixed Endpoints

  • GET /api/v1/parks/{park_slug}/rides/{ride_slug}/ - Now working correctly
  • All park ride detail API calls now function properly

Benefits

  1. API Reliability: Park ride detail endpoints now work as expected
  2. Historical Slug Support: Rides can be found even if their slugs have changed
  3. Consistent Patterns: Matches the established pattern used by Park model
  4. Future-Proof: Supports both current and historical slug lookups

Files Modified

  1. backend/apps/rides/models/rides.py
    • Added get_by_slug class method to Ride model
    • Implemented historical slug lookup functionality
    • Added proper type hints and documentation

Confidence Level

10/10 - The issue was clearly identified, the solution follows established patterns, and testing confirms the fix works correctly.