Does changing to_param() have any side effect?

In some book, it is recommended that to_param is changed to

class Story < ActiveRecord::Base

  def to_param
    "#{id}-#{name.gsub(/\W/, '-').downcase}"
  end

end

so that the URL is

http://www.mysite.com/stories/1-css-technique-blog

instead of

http://www.mysite.com/stories/1

so that the URL is more search engine friendly.

So probably to_param() doesn’t need to be used by other parts of Rails
that changing it may have any side effect? Or maybe the only purpose is
to construct a URL for linking?

Another thing is, won’t it require to limit the URL size to be less than
2k in length – will it choke IE if it is more than 2k or maybe the part
more than 2k is just ignored by IE and so the URL still works. It might
be better to be limited to 30 or 40 characters or something that will
make the URL not exceedingly long.

Also, the ri doc of to_param:

       class User < ActiveRecord::Base
         def to_param  # overridden
           name
         end
       end

if to_param is changed like that, then the link actually won’t work, as

http://www.mysite.com/stories/1-css-technique-blog

will work, but

http://www.mysite.com/stories/css-technique-blog

will not work as the ID is missing. Are there other ways to change the
to_param method?

Update: on second thought, maybe

http://www.mysite.com/stories/css-technique-blog

won’t work well if there are many webpages with similar title. but then

http://www.mysite.com/user/johnchan

will work. Will it be params[:id] being “johnchan”? So then we will
use

user = User.find_by_login_name(params[:id])

to get the user. So it just depends on how we use the param on the URL.

C:\ror>ri ActiveRecord::Base#to_param
--------------------------------------------

ActiveRecord::Base#to_param
to_param()
------------------------------------------------------------------------
Returns a String, which Action Pack uses for constructing an
URL to
this object. The default implementation returns this record’s
id as
a String, or nil if this record’s unsaved.

     For example, suppose that you have a User model, and that you

have
a +map.resources :users+ route. Normally, +user_path+ will
construct a path with the user object’s ‘id’ in it:

       user = User.find_by_name('Phusion')
       user_path(user)  # => "/users/1"

     You can override +to_param+ in your model to make +user_path+
     construct a path using the user's name instead of the user's

id:

       class User < ActiveRecord::Base
         def to_param  # overridden
           name
         end
       end

       user = User.find_by_name('Phusion')
       user_path(user)  # => "/users/Phusion"

Jian,

This was a common practice a while ago but I would recommend against
changing to_params. It will work but my experience has been that code
gets messy as you find fringe cases. I HIGHLY HIGHLY HIGHLY recommend
you look at norman’s friendly_id gem. It is extremely easy to setup
and all you do is drop one line of code in your model and everything
works like magic.

http://github.com/norman/friendly_id

Matt

On May 24, 2010, at 4:11 PM, Marnen Laibow-Koser wrote:

Huh?

The only case I come across after changing to_param is when I pass
params[:id] (= “123-foo-bar”) into find_by_id and forget to call to_i on
it. find() by itself will do the right thing, but find_by_id won’t.
Not a big deal though.

-philip

M Daubs wrote:

Jian,

This was a common practice a while ago but I would recommend against
changing to_params.

Why? I can’t think of a good reason.

It will work but my experience has been that code
gets messy as you find fringe cases.

Huh?

I HIGHLY HIGHLY HIGHLY recommend
you look at norman’s friendly_id gem. It is extremely easy to setup
and all you do is drop one line of code in your model and everything
works like magic.

http://github.com/norman/friendly_id

Yeah, there are several gems like that. They look great.

Matt

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

I don’t enjoy reinventing functionality when there’s already a good
gem to get the job done. Changing to_param will work but my
preference is to not change it because then I have to modify all of my
calls to find for every model class involved. And if I’m going to
change to_param, you might as well rip out the integer ID as well so
that you are SEO and human-optimized at the same time. With that
comes the responsibility to ensure another unique column which might
be trivial or may be a pain depending on your existing data
requirements. Nothing here is a deal breaker but the way I see it
it’s all a lot more work than just using friendly_id. Less code to
test and less code to break. That’s just my preference, though.
Everyone’s different.