---
title: How to customize ids in URLs in your Rails app
teaser: Override the `to_param` method on your object to customize how Rails builds
  the id to put in the URL.
tags: development,web,rails,ruby
author: Joël Quenneville
published_on: 2025-02-10
---

Rails’ URL helpers allow you to pass in an Active Record object and it will automatically infer the proper URL including the id (e.g. `link_to "Profile", @user`). How can we get this behavior for custom objects?

## Custom objects

Consider a custom `Image` class. We want URLs to look like `/images/cat.gif`.

Rails relies on the [to_param](https://api.rubyonrails.org/classes/ActiveModel/Conversion.html#method-i-to_param) method to generate identifiers in URLs. If we define it on our custom object it can now be used with `link_to` just like ActiveRecord objects can.

```ruby
class Image
  attr_reader :filename

  def to_param
    filename
  end
end
```

```erb
<%= link_to "Details", @image %>
<%# will generate <a href="/images/cat.gif">Details</a> %>
```

## Slugs

Because Rails URL-helpers aren't hard-coded to use ids but instead rely on `to_param` it allows us to build some fancier behaviors on top such as replacing identifiers with a prettier "slug". For example when linking to a tag on a blog, we might want a URL that looks like `tags/ruby` rather than `tags/1`.

To do this we can override the `to_param` method to use the name instead of the id. Keep in mind that you will be doing database lookups using this value so use something deterministic!

```ruby
class Tag < ApplicationRecord
  def to_param
    name.downcase
  end
end
```

Now when passing a user object into a link or form helper, it will generate a URL with our nice slug

```erb
<%= link_to "More #{@tag.name.titleize} content", @tag %>
<%# will generate <a href="/tags/ruby">More Ruby content</a> %>
```

This technique is how dedicated slug libraries like [FriendlyId](https://github.com/norman/friendly_id/blob/40b899a547624a50dbe44c5f337ef393e04a9152/lib/friendly_id/base.rb#L262-L268) work.

<aside class="warn">Now that <code>params[:id]</code> will be a tag name rather than an id, you will need to use <code>Tag.find_by!(name: params[:id])</code> to look up the the tag.</aside>

## ActiveModel compatibility

`to_param` is part of `ActiveModel`. You get if for free if you include [ActiveModel::Conversion](https://api.rubyonrails.org/classes/ActiveModel/Conversion.html) (it defaults to`id`). You can also just define the method directly on your plain old Ruby objects to make them play nicely with the URL helpers.

Writing your custom Ruby objects to be ActiveModel-compatible, whether or not you include any of the actual modules, allows them to integrate natively with Rails’ controller and view helpers. This gives you an experience that’s just as smooth as working with regular Active Record objects.
