API Reference
Table of contents
- EncodedId::Rails::Model
- EncodedId::Rails::PathParam
- EncodedId::Rails::SluggedPathParam
- EncodedId::Rails::ActiveRecordFinders
- EncodedId::Rails::Persists
- EncodedId::Rails::Configuration
- EncodedId::Rails::AnnotatedId
- EncodedId::Rails::SluggedId
- Single Table Inheritance (STI) Considerations
EncodedId::Rails::Model
The main module to include in your ActiveRecord models.
class User < ApplicationRecord
include EncodedId::Rails::Model
end
Including this module adds the following instance methods to your model:
Instance Methods
#encoded_id
Returns the encoded ID for this record, with optional annotation.
user = User.find(123)
user.encoded_id # => "user_p5w9-z27j"
The annotation prefix is determined by the #annotation_for_encoded_id method, which by default returns the model’s parameterized name.
#slugged_encoded_id
Returns the encoded ID with a human-readable slug prepended.
user = User.find(123)
user.name = "John Doe"
user.slugged_encoded_id # => "john-doe--user_p5w9-z27j"
The slug is generated by the #name_for_encoded_id_slug method, which must be implemented in your model.
#annotation_for_encoded_id
Returns the annotation prefix for the encoded ID. Override this method to customize.
class User < ApplicationRecord
include EncodedId::Rails::Model
def annotation_for_encoded_id
"usr" # Custom annotation
end
end
user = User.find(123)
user.encoded_id # => "usr_p5w9-z27j"
By default, returns the underscored model name.
#name_for_encoded_id_slug
Returns the string to use as the slug part of #slugged_encoded_id. Must be implemented in your model.
class User < ApplicationRecord
include EncodedId::Rails::Model
def name_for_encoded_id_slug
full_name.presence || "user-#{id}"
end
end
If not implemented, calling #slugged_encoded_id will raise an error.
Class Methods
.find_by_encoded_id(encoded_id)
Finds a record by its encoded ID.
# These all work:
User.find_by_encoded_id("user_p5w9-z27j") # Annotation included
User.find_by_encoded_id("p5w9-z27j") # Just the hash
User.find_by_encoded_id("john-doe--user_p5w9-z27j") # Slugged version
Returns nil if no record is found.
.find_by_encoded_id!(encoded_id)
Same as find_by_encoded_id, but raises ActiveRecord::RecordNotFound if no record is found.
User.find_by_encoded_id!("user_p5w9-z27j")
# => #<User id: 123, name: "John Doe">
User.find_by_encoded_id!("invalid-id")
# => ActiveRecord::RecordNotFound
.find_all_by_encoded_id(encoded_id)
Finds all records with the given encoded ID. Useful when the encoded ID encodes multiple IDs.
# Encoded ID that contains multiple record IDs
User.find_all_by_encoded_id("7aq6-0zqw")
# => [#<User id: 78>, #<User id: 45>]
.where_encoded_id(*encoded_ids)
Returns an ActiveRecord relation for the given encoded ID(s). Accepts multiple arguments or an array of encoded IDs.
# Single encoded ID
User.where_encoded_id("user_p5w9-z27j").where(active: true)
# Multiple encoded IDs as arguments
User.where_encoded_id("user_p5w9-z27j", "user_a2k8-3xqz")
# Array of encoded IDs
encoded_ids = ["user_p5w9-z27j", "user_a2k8-3xqz"]
User.where_encoded_id(encoded_ids)
# Mix with other query methods
User.where_encoded_id("user_p5w9-z27j", "user_a2k8-3xqz").where(active: true).order(:created_at)
This method handles all encoded ID formats:
- Annotated IDs:
"user_p5w9-z27j" - Slugged IDs:
"john-doe--user_p5w9-z27j" - Hash only:
"p5w9-z27j"
Error Handling:
- Raises
ActiveRecord::RecordNotFoundif any encoded ID isnil, blank, or an empty array is provided - Invalid encoded IDs that cannot be decoded result in an empty relation (no records found)
.encode_encoded_id(id)
Encodes a record ID using the model’s configuration.
User.encode_encoded_id(123) # => "p5w9-z27j"
.decode_encoded_id(encoded_id)
Decodes an encoded ID string back to an array of record IDs.
# Decode annotated ID
User.decode_encoded_id("user_p5w9-z27j") # => [123]
# Decode slugged ID
User.decode_encoded_id("john-doe--user_p5w9-z27j") # => [123]
# Decode hash only
User.decode_encoded_id("p5w9-z27j") # => [123]
# Returns nil for blank/nil input
User.decode_encoded_id(nil) # => nil
User.decode_encoded_id("") # => nil
# Returns empty array for invalid encoded IDs
User.decode_encoded_id("invalid!") # => []
This method handles all encoded ID formats (annotated, slugged, or hash-only) and returns an array because encoded IDs can encode multiple record IDs.
EncodedId::Rails::PathParam
Module to include in your model to make it use encoded IDs in URL helpers.
class User < ApplicationRecord
include EncodedId::Rails::Model
include EncodedId::Rails::PathParam
end
user = User.find(123)
user.to_param # => "user_p5w9-z27j"
Instance Methods
#to_param
Returns the encoded ID for use in URLs.
# In routes:
# resources :users, param: :encoded_id
# In views:
link_to "View User", user_path(user) # => "/users/user_p5w9-z27j"
EncodedId::Rails::SluggedPathParam
Module to include in your model to make it use slugged encoded IDs in URL helpers.
class User < ApplicationRecord
include EncodedId::Rails::Model
include EncodedId::Rails::SluggedPathParam
def name_for_encoded_id_slug
full_name
end
end
user = User.find(123)
user.name = "John Doe"
user.to_param # => "john-doe--user_p5w9-z27j"
Instance Methods
#to_param
Returns the slugged encoded ID for use in URLs.
# In routes:
# resources :users, param: :encoded_id
# In views:
link_to "View User", user_path(user) # => "/users/john-doe--user_p5w9-z27j"
EncodedId::Rails::ActiveRecordFinders
Module to include in your model to automatically handle encoded IDs in standard ActiveRecord finder methods.
class Product < ApplicationRecord
include EncodedId::Rails::Model
include EncodedId::Rails::ActiveRecordFinders
end
Important: This module should NOT be used with models that use string-based primary keys (e.g., UUIDs) as it will cause conflicts between string IDs and encoded IDs.
Class Methods (Overridden)
.find
Overrides the default ActiveRecord find method to automatically handle encoded IDs.
# Standard ActiveRecord finds by ID
Product.find(123) # => #<Product id: 123>
# Now also works with encoded IDs
Product.find("product_p5w9-z27j") # => #<Product id: 123>
Product.find("p5w9-z27j") # => #<Product id: 123>
Product.find("cool-product--product_p5w9-z27j") # => #<Product id: 123>
# Also handles encoded IDs containing multiple IDs
Product.find("z2j7-0dmw") # => [#<Product id: 78>, #<Product id: 45>]
Raises ActiveRecord::RecordNotFound if the ID can’t be found or if the encoded ID fails to decode.
.find_by_id
Overrides the default ActiveRecord find_by_id method to handle encoded IDs.
# Standard behavior
Product.find_by_id(123) # => #<Product id: 123>
# Now handles encoded IDs
Product.find_by_id("product_p5w9-z27j") # => #<Product id: 123>
# Returns nil for non-existent records (instead of raising an error)
Product.find_by_id("invalid-id") # => nil
Example Usage
class Product < ApplicationRecord
include EncodedId::Rails::Model
include EncodedId::Rails::ActiveRecordFinders
include EncodedId::Rails::SluggedPathParam # Optional
end
# Create a product and get its encoded ID
product = Product.create(name: "Example Product")
encoded_id = product.encoded_id # => "product_p5w9-z27j"
# Now you can use standard ActiveRecord methods with encoded IDs
Product.find(encoded_id) # => #<Product id: 1, name: "Example Product">
Product.find_by_id(encoded_id) # => #<Product id: 1, name: "Example Product">
# Use with slugged IDs
slugged_id = product.slugged_encoded_id # => "example-product--product_p5w9-z27j"
Product.find(slugged_id) # => #<Product id: 1, name: "Example Product">
# In controllers, you can simply use params[:id] directly
def show
@product = Product.find(params[:id]) # Works with regular IDs and encoded IDs
end
EncodedId::Rails::Persists
Module to include in your model to persist encoded IDs in the database.
class User < ApplicationRecord
include EncodedId::Rails::Model
include EncodedId::Rails::Persists
end
Requires the following database columns:
normalized_encoded_id(string): The encoded ID without formattingprefixed_encoded_id(string): The complete encoded ID with annotation
Instance Methods
#set_normalized_encoded_id!
Updates the persisted encoded ID columns for this record.
user = User.find(123)
user.set_normalized_encoded_id!
This method is called automatically when a record is created.
EncodedId::Rails::Configuration
Configuration for the Rails integration.
# In config/initializers/encoded_id.rb
EncodedId::Rails.configure do |config|
config.salt = "my-secret-salt"
config.id_length = 8
config.character_group_size = 4
config.group_separator = "-"
config.alphabet = EncodedId::Alphabet.modified_crockford
config.annotation_method_name = :annotation_for_encoded_id
config.annotated_id_separator = "_"
config.slug_value_method_name = :name_for_encoded_id_slug
config.slugged_id_separator = "--"
config.model_to_param_returns_encoded_id = false
config.encoder = :sqids
config.blocklist = []
end
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
salt | String | nil | Optional salt used for encoding (recommended for production) |
id_length | Integer | 8 | Minimum length of the encoded hash |
character_group_size | Integer | 4 | Split encoded string every X characters (set to nil to disable) |
group_separator | String | "-" | Character used to separate character groups |
alphabet | EncodedId::Alphabet | EncodedId::Alphabet.modified_crockford | The alphabet to use for encoding |
annotation_method_name | Symbol | :annotation_for_encoded_id | Method to call for annotation prefix |
annotated_id_separator | String | "_" | Separator between annotation and ID |
slug_value_method_name | Symbol | :name_for_encoded_id_slug | Method to call for slug value |
slugged_id_separator | String | "--" | Separator between slug and ID |
model_to_param_returns_encoded_id | Boolean | false | Whether all models should override to_param |
encoder | Symbol | :sqids | ID encoding engine (:hashids or :sqids) |
blocklist | Array or EncodedId::Blocklist | EncodedId::Blocklist.empty | Words to prevent in encoded IDs |
downcase_on_decode | Boolean | false | Whether to downcase encoded IDs before decoding |
EncodedId::Rails::AnnotatedId
Class for creating annotated IDs.
annotated_id = EncodedId::Rails::AnnotatedId.new(
id_part: "p5w9-z27j",
annotation: "user",
separator: "_"
)
annotated_id.annotated_id # => "user_p5w9-z27j"
EncodedId::Rails::SluggedId
Class for creating slugged IDs.
slugged_id = EncodedId::Rails::SluggedId.new(
id_part: "user_p5w9-z27j",
slug_part: "john-doe",
separator: "--"
)
slugged_id.slugged_id # => "john-doe--user_p5w9-z27j"
Single Table Inheritance (STI) Considerations
When using encoded_id with ActiveRecord Single Table Inheritance (STI), each class in the hierarchy generates its own unique salt by default, making encoded IDs incompatible across classes.
Default Behavior
By default, each class has its own salt:
- Parent class cannot decode child’s encoded IDs
- Child class cannot decode parent’s encoded IDs
- Sibling classes cannot decode each other’s encoded IDs
Sharing Salt Across STI Hierarchy
To make encoded IDs compatible across an STI hierarchy, override encoded_id_salt to use the parent class’s salt:
class Dog < Animal
def self.encoded_id_salt
EncodedId::Rails::Salt.new(Animal, EncodedId::Rails.configuration.salt).generate!
end
end
Important: Ensure all classes in the hierarchy use the same base class for salt generation to maintain consistency.
For comprehensive examples including practical API usage, polymorphic endpoints, and when to use shared vs separate salts, see the STI examples documentation.