Search code examples
ruby-on-railsroutesfriendly-id

Prepending a UUID to route to ensure uniqueness of slug


I'm using the friendly_id to add custom slugs to my models and their corresponding urls. Currently I have a setup where a Post belongs to a Board. There will undoubtedly be cases where a post will have an identical title to another but from a different board. Often times I've noticed sites (SO included) prepend a unique set of numbers before the slug to insure there are no issues with uniqueness:

https://stackoverflow.com/questions/123456/my-example-question

I was wondering what would be the best approach to accomplish this? This couldn't be done solely through the routes file because there still poses the possibility of two or more identical posts being created. Would it be a combination of altering my model, routes file, and configuration of the friendly_id gem?

My end goal is to have a url generated like this for my posts:

https://example.com/boards/example-board/123456/example-post

class Board < ApplicationRecord
  extend FriendlyId

  has_many :posts

  friendly_id :name, use: :slugged
end


class Post < ApplicationRecord
  extend FriendlyId

  belongs_to :board

  friendly_id :title, use: :slugged
end

resources :boards do
  scope module: :boards do
    resources :posts
  end
end

Solution

  • EDIT

    You can do something like this in your routes:

    resources :boards do
      resources :posts, path: ':board_real_id'
    end
    

    and add params[:board_real_id] to your query.

    OLD

    I don't think you need UUID for this (unless you want to). You can use candidates and if two posts have the same name and they belong to the same board, just insert the post's id and you'll be fine, you'll have something like https://example.com/boards/example-board/123456-example-post

    From: http://norman.github.io/friendly_id/file.Guide.html

    Since UUIDs are ugly, FriendlyId provides a "slug candidates" functionality to let you specify alternate slugs to use in the event the one you want to use is already taken. For example:

    friendly_id :slug_candidates, use: :slugged
    
      # Try building a slug based on the following fields in
      # increasing order of specificity.
      def slug_candidates
        [
          :name,
          [:id, :name]
        ]
      end