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.