Ruby on Rails
sluggable_finder

SluggableFinder

Ismael Celis (http://www.estadobeta.com)

This is a variation of acts_as_slugable, acts_as_permalink and whiny_finders.

This plugin allows models to generate a unique “slug” (url-enabled name) from any regular atribute.

Sluggable models can have a scope parameter so slugs are unique relative to a parent model.

The plugin also adds an ActiveRecord::Base#find_sluggable method that looks into the “slug” field. If not found, it raises an ActiveRecord::RecordNotFound exception so you can use it just like find_by_id

EXAMPLES

In your models (app/models)

class Category < ActiveRecord::Base
    has_many :posts
    sluggable_finder :title #slugifies the :title field into the :slug field
end

class Post < ActiveRecord::Base
    belongs_to :category
    has_many :comments
    sluggable_finder :title, :scope => :category_id #Post slugs are unique to the parent category
end

class Comment < ActiveRecord::Base
    belongs_to :post
    sluggable_finder :get_slug, :to => :permalink #creates slug from custom attribute and stores it in "permalink" field

    def get_slug #we define the custom attribute
        "#{post.id}-#{Time.now}" 
    end
end
In your routes (config/routes.rb)

map.post ‘posts/:post_slug’

In your controllers (app/controllers)

You can do Model.find_sluggable( param ) just like Model.find( id ). It will also raise a RecordNotFound exception so you can handle that in your custom rescue_action_in_public action (more on that on http://www.estadobeta.com/2007/05/06/activerecordrecordnotfound/#comment-17669 in Spanish for now).

The idea is that you keep your controller actions clean and handle Not Found errors elsewhere.

class PostsController < ApplicationController
    def show
        @post = Post.find_sluggable( params[:post_slug] ) #raises ActiveRecord::RecordNotFound if not found
    end
end

INSTALLATION

Download it to your Rails app as usual.

.script/plugin install http://code.estadobeta.com/plugins/sluggable_finder

Generate the migration to add the “slug” field to you model (“slug” is the default. You can use other field names).

.script/generate migration AddSlugToBlogs

class AddSlugToBlogs < ActiveRecord::Migration
  def self.up
    add_column :blogs, :slug, :string
  end

  def self.down
    remove_column :blogs, :slug
  end
end
#migrate it
rake db:migrate

Use it as in the EXAMPLES part above.
Questions to Ismael at http://www.estadobeta.com