A Social Network in Rails: Elegant permalinks
In this post we’re adding permalinks to a Rails app using the friendly_id gem.
Let’s say you have a `User` and a `Photo` model in your app, and a user has_many :photos.
To add a permalink to a photo post that looks like this:
www.nice-pics.com/berners-lee/photos/my-first-site
Add friendly_id to your Gemfile:
gem “friendly_id”
Add the permalink schema to your routes.rb:
get “:user_id/photos/:photo_id”, to: “photos#show”, as: :photo_permalink
Now, add the friendly_id scheme to your User:
class User::HasFriendlyId < ActiveRecord::Base extend FriendlyId friendly_id :slug_candidates
has_many :photos
def slug_candidates # if there’s a username clash, use the full email [:username, :email] end
def username
email.split(”@“).first
end
end
and to your Photo:
class Photo < ActiveRecord::Base include Rails.application.routes.url_helpers extend FriendlyId friendly_id :slug_candidates, use: :scoped, scope: :user
belongs_to :user
def slug_candidates # if there’s a name clash, use the photo’s name, width & height [:name, -> { ”#{name}-#{width}-#{height}” }] end
def permalink photo_permalink_url( user_id: user.friendly_id, photo_id: friendly_id, host: “https://www.example.com” ) end end
Add the slugs to your db via migrations:
rails generate migration add_slug_to_photo slug:string rails generate migration add_slug_to_user slug:string
And finally, add the controller action:
class ClipsController < ApplicationController def show user = User.friendly.find(params[:user_id]) @clip = user.photos.friendly.find(params[:clip_id]) end end
Done! Now, if you do in your Rails console:
> user = User.create(email: berners-lee@internet.org)
user.photos.create(name: my-first-site, width: 200, height: 300)
The following link will work: www.nice-pics.com/berners-lee/photos/my-first-site
And, if we add another photo with the same name, its link will still look nice:
> user.photos.create(name: my-first-site, width: 400, height: 800)
www.nice-pics.com/berners-lee/photos/my-first-site-400-800
Human readable, clear, and permanent. Nice :D
