dm-is-slug

DataMapper plugin for creating and slugs (and permalinks).

Basics

Slugs are unique identifiers in a url that endeavour to be more human-readable.

Say you have a blog where you like to write about Ruby (it's a long shot, I know). You've just written an insigtful expository on DataMapper, and you're ready to pass that URL around for people to read.

This gem will turn:

/category/4/posts/12

into:

/category/ruby/posts/datamapper_is_the_bees_knees

Now the whole world will know exactly what you're sending them. Isn't that nice? The answer is "yes".

Getting started

Let's say we have a post-class, and we want to generate permalinks or slugs for all posts.

class Post
  include DataMapper::Resource

  property :id, Serial
  property :title, String
  property :content, Text

  belongs_to :user

  # here we define that it should have a slug that uses title as the slug
  # it will generate an extra slug property of String type, with the same size as title
  is :slug, :source => :title
end

Let's Say we need to define a slug based on a method instead of a property.

class User
  include DataMapper::Resource

  property :id, Serial
  property :email, String
  property :password, String

  has n, :posts

  # we only want to strip out the domain name 
  # and use only the email account name as the permalink
  def slug_for_email
    email.split("@").first
  end

  # here we define that it should have a slug that uses title as the permalink
  # it will generate an extra slug property of String type, with the same size as title
  is :slug, :source => :slug_for_email, :size => 255
end

You can now find objects by slug like this:

post = Post.first(:slug => "your_slug")

Merb routes

Building pretty routes in Merb is dead simple, especially with all this slugtacular mojo going on.

Here's a quick example route:

match("/posts/:slug").to(:controller=>:posts,:action=:index).name(:post)

Let's make a quick post to our fictional blog:

Post.create(:title => "Pretty URLs in Merb are easy", :content => "I feel like a good person for making the Internets pretty.")

Now the URL generation is as easy as:

url(:post,@post)  #=>  /posts/pretty_urls_in_merb_are_easy

Pretty slick, no?

Plays nice with nested routes and resources

Say we want to have pretty URLs for a forum (and who wouldn't?)

First, let's set up a couple of models:

class Forum
  include DataMapper::Resource

  property :id, Serial
  property :name, String
  property :description, Text

  is :slug, :source => :name
end

class Topic
  include DataMapper::Resource

  property :id, Serial
  property :subject, String
  property :description, Text

  is :slug, :source => :subject
end

OK, now we'll make some nested resources in Merb in router.rb:

resources :forums, :identify => :forum_slug do 
  resources :topics, :identify => :topic_slug
end

This will generate CRUD routes that match the following pattern:

/forums/:forum_slug/topics/:topic_slug

Since #forum_slug and #topic_slug are aliases for #slug (both getters & setters), in your resource controller you can get the models via:

@forum = Forum.get(params[:forum_slug])

@topic = Topic.get(params[:topic_slug])

and generating the URL is as easy as:

resource(@forum,@topic)

Mutability

By default, all slugs are mutable. That is, they can (and will) be updated when the source property changes.

If you want to make a slug immutable (a permalink), you can pass :mutable => false as an option:

is :slug, :source => :name, :mutable => false

Now your slug will never change once created.