Skip to content

Conversation

@oehlschl
Copy link
Member

@oehlschl oehlschl commented Sep 26, 2025

Summary

This PR adds a new configuration option treat_numeric_as_conflict to resolve the ambiguity where Model.friendly.find("123") could return either a record with slug="123" OR a record with id=123.

When enabled, purely numeric slug candidates are treated as conflicts and resolved using UUID suffixing, ensuring all slugs contain non-numeric characters that eliminate lookup ambiguity.

Changes

  • Added treat_numeric_as_conflict configuration option to Slugged::Configuration
  • Updated SlugGenerator to detect and reject purely numeric slugs when enabled
  • Added purely_numeric_slug? helper method using Integer() validation (consistent with potential_primary_key?)
  • Expanded test coverage for both default behavior and numeric prevention

Usage

class Product < ApplicationRecord
  extend FriendlyId
  friendly_id :name, use: :slugged
  friendly_id_config.treat_numeric_as_conflict = true
end

# Results:
Product.create(name: "123")     # slug: "123-f9f3789a-daec-4156-af1d-fab81aa16ee5"
Product.create(name: "abc123")  # slug: "abc123" (unchanged)

Testing Done

  • All existing tests pass
    • Verified backward compatibility (default behavior unchanged)
  • Added comprehensive test coverage for new functionality
    • Tests cover edge cases: zero, large numbers, alphanumeric combinations
    • Verified UUID conflict resolution works for multiple numeric slugs

Deploy Notes

  • No breaking changes: This is a new opt-in configuration option
  • No migration required: Uses existing slug storage and UUID conflict resolution
  • Safe to deploy: Feature is disabled by default, maintaining all existing behavior
  • Rollback safe: Simply remove configuration option to disable

Fixes

Addresses the ambiguous lookup issue reported in norman#276 where User.find('123-foobar') could incorrectly return a user with id=123 instead of searching for the intended slug.

@oehlschl oehlschl force-pushed the feature/treat-numeric-as-conflict branch from 3864f3c to d0c552d Compare September 26, 2025 06:25
@oehlschl
Copy link
Member Author

Opened as norman#1037

@oehlschl oehlschl closed this Sep 26, 2025
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