rodrigoalvesvieira
rodrigoalvesvieira

Reputation: 8062

Better, non numerical and non sequencial ids for ActiveRecord

I use ActiveRecord in my Rails 4.1.1 app and I am persisting the objects in the database but I really don't like the ids assigned to my objects (1, 2, 3, and so on) I want these ids to be non-integer and non-sequencial, just like the MongoId gem does.

How can I do this?

Upvotes: 0

Views: 89

Answers (1)

SteveTurczyn
SteveTurczyn

Reputation: 36860

I'm assuming you want this change because you don't like how the ids are exposed in the url...

http://my_application.com/posts/3.html

There's no other reason to change the ids... they do the job they're supposed to and they're (excepting for the above situation) internal to the app.

The technique you might want to consider is using "slugs"

Create an attribute in your model called slug which could be your model "title" or "name" but in a url-friendly format... create it automatically in a before_save action

class Post < ActiveRecord::Base
  before_save :create_slug

  def create_slug
    #strip the string
    slug = title.strip

    #blow away apostrophes
    slug.gsub! /['`]/,""

    # @ --> at, and & --> and
    slug.gsub! /\s*@\s*/, " at "
    slug.gsub! /\s*&\s*/, " and "

    #replace all non alphanumeric, underscore or periods with underscore
     slug.gsub! /\s*[^A-Za-z0-9\.\-]\s*/, '_'  

     #convert double underscores to single
     slug.gsub! /_+/,"_"

     #strip off leading/trailing underscore
     slug.gsub! /\A[_\.]+|[_\.]+\z/,""

     #make sure the slug is unique...
     unique = false
     appendix = ""
     counter = 0
     until unique
       test_slug = slug + appendix
       test_object = self.class.find_by_slug(test_slug)
       unique = true unless test_object && test_object != self
       counter += 1
       appendix = "_#{counter}"
     end

     self.slug = test_slug
  end
end

then create a 'to_param' method in your class... this will create the "user_friendly" id that will appear in the urls

def to_param
  slug
end

Finally, you need to replace your "find" methods to "find_by_slug" (so that it searches on slug, not on the original id)

@post = Post.find_by_slug(params[:id])

All this will give you a nicer url...

http://my_application.com/posts/my_post_about_flowers.html

this is a good reference about slugging http://blog.teamtreehouse.com/creating-vanity-urls-in-rails

And the slug method I show was adapted from this SO post...

Best way to generate slugs (human-readable IDs) in Rails

Upvotes: 2

Related Questions