# Referencing REST resources with something other than ids

**URL:** <https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657>\
**Category:** Rails\
**Created:** [July 5, 2007, 6:40pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657 "2007-07-05T18:40:47Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 5, 2007, 6:40pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/1 "2007-07-05T18:40:47Z")

</div>

Hello.  
I got a REST URL personalization issue… Here is an example to  
explain:

If have two nested resources set like this in “routes.rb”:

map.resources :teams do |teams|  
teams.resources :players  
end

So, some teams will be accessible with URL such that:

/teams/42  
/teams/42/edit

and the players by some of the form:

/team/42/players  
/team/42/players/18  
/team/42/players/new

etc…

Is there a convenient way do not use the “id” column of the “team” and  
“player” models but another one (e.g. “name”, supposing it’s unique)  
to have nicer URLs but keeping the ability to use \*\_path helpers?  
So, I dream of URLs such that, keeping the same example:

/teams/mylovelyteam  
/teams/mylovelyteam/players  
/teams/mylovelyteam/players/new  
/teams/mylovelyteam/players/theleader

I hope my explanation is understandable…

Thanks.

aurels, belgium

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 5, 2007, 6:53pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/2 "2007-07-05T18:53:49Z")

</div>

On 7/6/07, AurÃ©lien Malisart [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> end  
> /team/42/players/new  
> /teams/mylovelyteam/players/new  
> /teams/mylovelyteam/players/theleader
> 
> I hope my explanation is understandable…
> 
> Thanks.
> 
> aurels, belgium

I know of one way. I can’'t say if it’s the best or not.

When a route is generated, the id method of the object is not actually  
called. It’s just the default. The magic method is to\_param

So in your method if you put

def to\_param  
self.name  
end

Then this should give you the routes that your after. You will need to  
escape it though so it doesn’t give you bad urls. However…

I believe that by doing this ( I haven’t tried it myself ) it will still  
call the parameter :id, but you will need to find\_by\_name in your  
controllers.

so  
was ==\> Team.find( params[:id] )  
Now ==\> Team.find\_by\_name( params[:id] )

The way I have done it to avoid this is to include the id still. But I  
don’t know if I’ll keep it like this for ever.  
/team/1-my-lovely-team

This way ruby still interprets the id as an integer and I can use it as  
normal.

Here’s the code I’m using. I got the escaping code from Rick O.'s  
permalink\_fu plugin

cattr\_reader :translation\_to, :translation\_from  
@@translation\_to = ‘ascii//ignore//translit’  
@@translation\_from = ‘utf-8’

# Ripped directly from permalink\_fu by Rick O.

def escape\_slug(str)  
s = Iconv.iconv(self.class.translation\_to,  
self.class.translation\_from, str).to\_s  
s.gsub!(/\W+/, ’ ') # all non-word chars to spaces  
s.strip! # ohh la la  
s.downcase! #  
s.gsub!(/\ +/, ‘-’) # spaces to dashes, preferred separator char  
everywhere  
s  
end

def to\_param  
escape\_slug “#{self.id}-#{self.name}”  
end

HTH

Daniel

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 5, 2007, 7:16pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/3 "2007-07-05T19:16:51Z")

</div>

The first solution works good 😉  
So thanks! Hope this will help some else!

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 5, 2007, 7:26pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/4 "2007-07-05T19:26:52Z")

</div>

Aurélien Malisart wrote:

> So, some teams will be accessible with URL such that:  
> etc…
> 
> I hope my explanation is understandable…
> 
> Thanks.
> 
> aurels, belgium

Yes, sort of.

I’ve got a project that does this with one of it’s controllers and it  
works great. What you need to understand is that the RESTful routes  
will just pass whatever comes after /teams/ in the url as the :id in the  
hash. So, what you would do in your controller is…

Team.find\_by\_name(params[:id])

This then assumes that you’ll always, always, always get the team name  
in the url, and will never be trying to call /teams/42, as that would  
just look for a team named “42”, which may or may not exist. One  
option is, if you’re certain you’ll NEVER have a team who’s name is a  
number, then you could do a REGEX check on the params[:id] and if it  
purely numbers, then do a normal find by :id, otherwise lookup by name  
with the params[:id] that isn’t really an :id.

–  
[http://www.5valleys.com/](http://www.5valleys.com/)

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 5, 2007, 8:35pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/5 "2007-07-05T20:35:00Z")

</div>

> Here’s the code I’m using. I got the escaping code from Rick O.'s  
> permalink\_fu plugin

You can, of course, just install the plugin 🙂

[http://svn.techno-weenie.net/projects/plugins/permalink\_fu/README](http://svn.techno-weenie.net/projects/plugins/permalink_fu/README)

–  
Rick O.  
[http://lighthouseapp.com](http://lighthouseapp.com)  
[http://weblog.techno-weenie.net](http://weblog.techno-weenie.net)  
[http://mephistoblog.com](http://mephistoblog.com)

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 6, 2007, 3:14am UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/6 "2007-07-06T03:14:50Z")

</div>

> Can this be used for the purpose outlined previously, just to provide a  
> slug, or do I need to use it with the date prefix, and a seperate db column?

The db column is so you’re not constantly escaping your titles. It  
also ensures that the permalink doesn’t change each time you tweak the  
title, which can be bad for SEO. Still, you can use  
PermalinkFu.escape to manually escape in a #to\_param method if you  
want.

–  
Rick O.  
[http://lighthouseapp.com](http://lighthouseapp.com)  
[http://weblog.techno-weenie.net](http://weblog.techno-weenie.net)  
[http://mephistoblog.com](http://mephistoblog.com)

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 6, 2007, 3:24am UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/7 "2007-07-06T03:24:50Z")

</div>

On 7/6/07, Rick O. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> want.
> 
> –  
> Rick O.  
> [http://lighthouseapp.com](http://lighthouseapp.com)  
> [http://weblog.techno-weenie.net](http://weblog.techno-weenie.net)  
> [http://mephistoblog.com](http://mephistoblog.com)

Just so I understand, I don’t want to be a pain in the arse.

With the way that I’m doing it if the title changes it doesn’t matter to  
the  
app, since the id is at the start of the slug, is this still bad for SEO  
since the link that the SE has is still valid?

Do I need to have the date prefix  
/blah/2007/07/07/permalink\_fu

Cheers  
Daniel

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 6, 2007, 4:17pm UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/8 "2007-07-06T16:17:44Z")

</div>

> What you need to understand is that the RESTful routes  
> will just pass whatever comes after /teams/ in the url as the :id in the hash

I do 😉

> So, what you would do in your controller is…
> 
> Team.find\_by\_name(params[:id])

That’s what I’m doing actually.

Thanks.

---

<div class="post-metadata">

**Author:** ![AurSSSSlien\_Malisar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d78d45/32.png) [@AurSSSSlien\_Malisar](https://www.ruby-forum.com/u/AurSSSSlien_Malisar)\
**Post date:** [July 6, 2007, 2:47am UTC](https://www.ruby-forum.com/t/referencing-rest-resources-with-something-other-than-ids/108657/9 "2007-07-06T02:47:49Z")

</div>

On 7/6/07, Rick O. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Rick O.  
> [http://lighthouseapp.com](http://lighthouseapp.com)  
> [http://weblog.techno-weenie.net](http://weblog.techno-weenie.net)  
> [http://mephistoblog.com](http://mephistoblog.com)

Rick,

Can this be used for the purpose outlined previously, just to provide a  
slug, or do I need to use it with the date prefix, and a seperate db  
column?

Cheers  
Daniel
