Fetching latest commit…
Cannot retrieve the latest commit at this time.
|Failed to load latest commit information.|
= FriendlyId FriendlyId is a plugin for Ruby on Rails which allows you to work with human-friendly strings as well as numeric ids for ActiveRecords. == The Problem Numeric id's for your database records are perfect most of the time, but present some problems when used in URL's: - They're ugly and impersonal. - They make URL's harder to remember. - They can give a window into your database - people can fiddle with your urls by incrementing id's. - They can give a hint about the number of records in your database. - They are bad for search engine optimization. However, text-based ids in URL's present some problems too: - They can change, breaking your URL's. - They can have invalid URL characters, breaking your links in some browsers. - It can be tricky to ensure they're always unique. FriendlyId lets you use textual id's for your active records while mostly avoiding these problems so that you can go from: OLD AND BUSTED: http://www.example.com/members/12 to NEW AND HOT: http://www.example.com/members/joe == How it works === Scenario 1: You already have a unique string column in your model. This is the usual case if you have a member/user model with a unique login/nickname/username column. In this case, all you need to do is add this to your model: has_friendly_id :login and you can then write code like this: @member = Member.find("joe") # the old Member.find(1) still works, too. @member.to_param # returns "joe" redirect_to @member # The URL would be /members/joe === Scenario 2: You want id's based on a not-necessarily unique string column in your model. This would be the typical case if you have a Posts/Articles model with titles, and you want the titles turned into slugs so you can have URL's like http://www.example.com/posts/new-version-released Here you would include this in your model: has_friendly_id :title, :use_slug => true and you can then write code like this: @post = Post.find("new-version-released") # Post.find(1) still works, too @post.to_param # returns "new-version-released" redirect_to @post # The URL would be /posts/new-version-released Now in your controllers, if you want to prevent people from accessing your models by numeric id, you can detect whether they were found by the friendly_id: @post.find(params[:id]) raise "some error" if !@post.found_using_friendly_id? or, you can 301 redirect if the model was found by the numeric id if you don't care about numeric access, but want the SEO value of the friendly_id: @post.find(params[:id]) redirect_to @post, :status => 301 if @post.has_better_id? The "has_better_id?" method returns true if the model was found with the numeric id, or with an outdated slug. ==== What if I change the title? One of the problems with using text-based id's in URL's is that if you change the id, your URL's using the old id all break. This could break people's bookmarks, and your search engine listings. Sometimes this doesn't matter, but often it does. Friendly_id will record changes to slugs so that you can do a 301 redirect to the new URL: def find_record_using_friendly_id @post = Post.find(params[:id]) redirect_to @post, :status => :moved_permanently if @post.has_better_id? end ==== What if the title isn't unique? Friendly_id will append a number to the end of the id to keep it unique if necessary: - /posts/new-version-released - /posts/new-version-released-2 - /posts/new-version-released-3 - etc. ==== Why not just override to_param with the id followed by a dasherized string? That works fine sometimes, but makes ugly urls: - OLD AND BUSTED: http://www.example.org/profiles/12-joe - NEW AND HOT: http://www.example.org/profiles/joe Also, these URL's will all point to the same content: - http://www.example.org/posts/12-i-love-joe - http://www.example.org/posts/12-i-hate-joe - http://www.example.org/posts/12-this-is-getting-kinda-ridiculous Search engines, especially Google, will penalize you for having duplicate content if you have more than one URL pointing to the same content. Also, any person can still simply increment the id part of the url, and gain a level of access to your data that you may not wish them to have. ==== What about non-ascii characters? Just do this: has_friendly_id :title, :use_slug => true, :strip_diacritics => true If you are not using slugs, you'll have to do this manually for whatever value you're using as the friendly_id. Also note, for this to work, you must install the "unicode" and "iconv" gems. == Subversion repository: http://svn.randomba.org/friendly_id A month of so after Rails 2.1 is released with support for plugins tracked via git, the subversion repository will be taken offline, and the git repository will be the way to go. For now, development is done using git but all changes are backported to the svn repository to support current users. == Git repository: firstname.lastname@example.org:norman/friendly_id.git == Setup: - script/plugin install http://svn.randomba.org/friendly_id/trunk - script/generate friendly_id_migration - rake db:migrate - now add some code to your models: e.g., <tt>has_friendly_id :title, :use_slug => true</tt> - if you are using slugs, then do rake friendly_id:make_slugs MODEL=MyModelName Then every so often, or perhaps every day via cron, you can do: rake:friendly_id:remove_old_slugs This will remove any old slugs for friendly ids that have changed. The default is to remove dead slugs older than 45 days, but you can change that by doing: rake:friendly_id:remove_old_slugs DAYS=60 == Bugs: At the moment, Model.exists? fails when using the slug (reported by Chris Nolan). Finder options are ignored when using slugs; this code returns results when it should not: Post.find_using_friendly_id(slugs(:one).name, :conditions => "1 = 2") This bug was reported by Dan Blue. These bugs part of a general pattern of not acting enough like ActiveRecord::Base, something I will address when I have a little more time. There probably are more bugs. If you find any, please contact the developers, or leave a comment at our site at: http://randomba.org. == Credits: Friendly_id was created by Norman Clarke (email@example.com[mailto:firstname.lastname@example.org]) and Adrian Mugnolo (email@example.com[mailto:firstname.lastname@example.org]). == Similar Plugins: friendly_identifier - Provides fully textual slugs, but no slug versioning. http://agilewebdevelopment.com/plugins/friendly_identifier acts_as_friendly_param - Versions slugs, but uses a to_param override, leaving ids in the url. http://agilewebdevelopment.com/plugins/acts_as_friendly_param acts_as_slugable - Provides fully textual slugs, but no slug versioning. http://agilewebdevelopment.com/plugins/acts_as_slugable acts_as_sluggable - Uses a to_param override, leaving ids in the url. Doesn't do versioning. http://agilewebdevelopment.com/plugins/acts_as_sluggable == Legal: Copyright (c) 2008 Norman Clarke and Adrian Mugnolo, released under the MIT license.