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

4 comments:

  1. FriendlyId author here - thanks for the nice writeup! One small quibble - although you can add them if you want to, it's not strictly necessary to create special routes for permalinks - FriendlyId will handle redirecting to the permalink for code like `redirect to @user` automatically.

    ReplyDelete
  2. Hey to everyone, it’s my first visit of the blog site; this blog includes awesome and actually best info for the visitors.
    mediaonlines.com

    ReplyDelete
  3. The Yoast SEO plugin also gives some recommendations for internal linking to other relevant content on your website.
    xenforo ads manager

    ReplyDelete