prefixed_ids

repository·main·Indexed 19 days ago

https://github.com/excid3/prefixed_ids

A Ruby on Rails gem that generates human-friendly, prefixed IDs by hashing a record's primary key using Hashids. It integrates with Rails' find and to_param methods, providing tools to encode/decode IDs, secure them with global or per-model salts, and look up records across registered models using PrefixedIds.find.

Tokens
3K
Snippets
17
Records
17
Agent score
63%

What's inside prefixed_ids

  1. Secure your IDs with a salt

    main

    To prevent users from reverse-engineering your IDs, you should use a salt. This makes the hashed values unguessable.

    You can define a Global Salt in an initializer or a Per Model Salt directly in the model declaration.

    # Global Salt
    # config/initializers/prefixed_ids.rb
    PrefixedIds.salt = "salt"
    
    # Per Model Salt
    class User < ApplicationRecord
      has_prefix_id :user, salt: "usersalt"
    end
  2. Prefix IDs in ActiveRecord associations

    main

    When using has_prefix_id, the library extends associations to support prefixed IDs:

    belongs_to associations: If the associated model uses has_prefix_id, a helper method #{association_name}_prefix_id is generated. This allows you to get or set the association using the prefixed string instead of the foreign key integer.

    has_many associations:

    • The relation is extended with prefix_ids, allowing you to call association.prefix_ids to get prefixed strings for all members of the collection.
    • The has_many method is extended to include ClassMethods (like find_by_prefix_id) on the association proxy.
    class Post < ApplicationRecord
      belongs_to :user
    end
    
    post = Post.first
    post.user_prefix_id # => "user_abc123"
    post.user_prefix_id = "user_xyz789" # Sets the foreign key via decoding
  3. Add `has_prefix_id` to a Rails model

    main

    To use friendly prefixed IDs in a Ruby on Rails model, include the has_prefix_id macro in your class. This enables encoding the model's ID into a prefixed string (e.g., user_abc123) and provides several helper methods for finding and decoding these IDs.

    By default, has_prefix_id enables:

    • Finder: Overrides find to support prefixed IDs and adds find_by_prefix_id.
    • ToParam: Overrides to_param so that model.to_param returns the prefixed ID.
    • Attribute: Adds methods to encode/decode IDs and extends associations.

    You can disable these features using the following options:

    • override_find: false
    • override_param: false
    • fallback: false (disables fallback decoding if the ID is invalid)
    class User < ApplicationRecord
      has_prefix_id :user
    end
  4. Integrate PrefixedIds with Rails via the Engine

    main

    The PrefixedIds::Engine automatically integrates the library with Rails. It uses a Rails initializer to hook into ActiveRecord. When ActiveRecord is loaded, the PrefixedIds::Rails module is included, which provides the necessary functionality for using prefixed IDs within your Rails models.

    # The engine automatically performs the following when the gem is loaded in a Rails app:
    ActiveSupport.on_load(:active_record) do
      include PrefixedIds::Rails
    end
  5. Query records by prefixed ID

    main

    The gem provides several ways to find records using their prefixed ID string:

    1. Automatic find override: By default, Model.find("prefix_id") works seamlessly. Note that find still supports regular primary keys (e.g., User.find(1) still works).
    2. Manual lookup (if overrides are disabled): If you have set override_find: false in your model configuration, use:
      • Model.find_by_prefix_id("prefix_id"): Returns the record or nil.
      • Model.find_by_prefix_id!("prefix_id"): Raises an exception if the record is not found.

    To disable the automatic find and to_param overrides, use the following configuration:

    class User < ApplicationRecord
      has_prefix_id :user, override_find: false, override_param: false
    end
  6. Find any model using a prefixed ID

    main

    If you have a prefixed ID but do not know which model it belongs to, you can use PrefixedIds.find. This behaves similarly to Rails' GlobalID.

    PrefixedIds.find("user_5vJjbzXq9KrLEMm3")
    #=> #<User>
    
    PrefixedIds.find("acct_2iAnOP0xGDYk6dpe")
    #=> #<Account>
  7. Generate prefixed IDs in models using `has_prefix_id`

    main

    To autogenerate prefixed IDs, add has_prefix_id :prefix to your model.

    Important: You must place has_prefix_id before your associations, as it overrides has_many to include prefix ID helpers.

    By default, this overrides to_param so that @model.to_param returns the prefixed string (e.g., user_12345abcd).

    class User < ApplicationRecord
      has_prefix_id :user
    end
  8. Configure PrefixedIds global settings

    main

    You can customize the encoding behavior globally via PrefixedIds configuration. These settings affect how Hashids generates the encoded portion of the ID.

    Available configuration keys:

    • delimiter: The character used to separate the prefix from the encoded ID (default: _).
    • alphabet: The characters used for encoding (default: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890).
    • minimum_length: The minimum length of the encoded ID portion (default: 24).
    • salt: The salt used for Hashids (default: "").
    PrefixedIds.delimiter = "-"
    PrefixedIds.salt = "my_secret_salt"
    PrefixedIds.minimum_length = 16
  9. Customize prefix ID configuration

    main

    You can fine-tune how prefixed IDs are generated and how they are looked up using several options in has_prefix_id:

    • prefix: The string prefix (e.g., :acct).
    • minimum_length: The minimum length of the hashed portion.
    • salt: A specific salt for this model.
    • fallback: If set to false, find will only accept prefixed IDs and will no longer accept regular integer primary keys.
    • override_find: Boolean to enable/disable overriding Model.find.
    • override_param: Boolean to enable/disable overriding to_param.
    class Account < ApplicationRecord
      has_prefix_id :acct, minimum_length: 32, override_find: false, override_param: false, salt: "", fallback: false
    end
  10. Encode an ID into a prefixed string

    main

    The encode method converts a numeric ID into a prefixed, obfuscated string. The resulting format is {prefix}{delimiter}{hashid}. The internal hashid includes a constant TOKEN (123) to ensure the integrity of the encoded value.

    Returns nil if the provided id is nil.

    # Assuming prefix_id_handler is initialized with prefix 'user' and delimiter '/'
    # and the internal hashid for ID 1 is 'abc'
    prefix_id_handler.encode(1) # => "user/abc"
  11. Split a prefixed ID into prefix and ID

    main

    The PrefixedIds.split_id(prefix_id, delimiter) method splits a string into its prefix component and its encoded ID component using the configured delimiter.

    prefix, id = PrefixedIds.split_id("user_abc123")
    # prefix => "user"
    # id => "abc123"