0

I noticed on the docs it says: Previous versions of FriendlyId appended a numeric sequence to make slugs unique, but this was removed to simplify using FriendlyId in concurrent code.

Is there any way to revert back to this format? My model only has name so there aren't any other viable slug candidates and (time or date wouldn't make sense in this case for slug candidates).

How can I change this (current format):

car.friendly_id #=> "peugeot-206"
car2.friendly_id #=> "peugeot-206-f9f3789a-daec-4156-af1d-fab81aa16ee5"
car3.friendly_id #=> "peugeot-206-f9dsafad-eamj-2091-a3de-fabsafafdsa5"

Into this:

car.friendly_id #=> "peugeot-206"
car2.friendly_id #=> "peugeot-206-1"
car3.friendly_id #=> "peugeot-206-2"
Onichan
  • 4,476
  • 6
  • 31
  • 60

5 Answers5

3

Old behaviour was implemented in special module. But at the moment it has not been released yet. So, if you want to restore old behaviour you can switch friebdly_id in your Gemfile on Github and add sequentially_slugged to the modules list.

kimrgrey
  • 562
  • 2
  • 10
  • 1
    this has since been released and can be utilized by doing use: :sequentially_slugged instead of :slugged – chrickso Apr 15 '18 at 18:17
2

I realize you said

(time or date wouldn't make sense in this case for slug candidates)

But in assuming you we're only referring to the string format of time and not unix which is a numeric sequence then I came up with this workaround to your problems/concerns:

  1. your model only has name attribute
  2. you can't use id to append to the slug because it hasn't been created yet
  3. you want the slugs to be uniq and incrementing
  4. you don't want to use UUID

# app/models/car.rb
class Car < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, use: :slugged

  def normalize_friendly_id(string)
    incremented_number = (Time.now.to_f * 1000000).to_i
    "#{super}-#{incremented_number}"
  end
end

So now this works

car1 = Car.create(name: "peugeot")
car2 = Car.create(name: "peugeot")
car3 = Car.create(name: "peugeot")

car1.friendly_id #=> "peugeot-1451368076324115"
car2.friendly_id #=> "peugeot-1451368076457560"
car3.friendly_id #=> "peugeot-1451368076460087"

Note: the numbers are incrementing

Time.now.to_f * 1000 would be miliseconds and I'm using Time.now.to_f * 1000000 which is MICROSECONDS <- that's one millionth of a second. It's NOT going to be created at the same time and therefore won't run into slug conflicts. And if someone out there thinks it could then just add a few more zeros to that multiplier.

Community
  • 1
  • 1
MilesStanfield
  • 4,571
  • 1
  • 21
  • 32
  • 2
    Is there a better way instead of having such a long slug? Its not much better than using the hash and also reveals the created time (which may not be something you want to reveal to the end user). – Onichan Jan 01 '16 at 05:45
1

Example use of sequentially_slugged

class Pipeline < ApplicationRecord
  extend FriendlyId

  friendly_id :name, use: :sequentially_slugged

  belongs_to :user

  scope :published, -> { where(published: true) }
end
Dorian
  • 7,749
  • 4
  • 38
  • 57
0

create a file in /config/initializers/slugged.rb

This works for me

module FriendlyId::Slugged
  def resolve_friendly_id_conflict(candidates)
    column = friendly_id_config.slug_column
    separator = friendly_id_config.sequence_separator
    slug = normalize_friendly_id(candidates.first)
    sequence = self.class.where("#{column} like '#{slug}#{separator}%'").count + 2
    "#{slug}#{separator}#{sequence}"
  end
end

Output will be

for first record  => firstname-lastname

for second record => firstname-lastname-2

for third record  => firstname-lastname-3
manish nautiyal
  • 2,556
  • 3
  • 27
  • 34
-1

There are good reasons that "serial number" was replaced by UUID (race conditions).
I normally use an additional slug candidate with the ID, that is maintained uniq by the db and much shorter than an UUID:

[ [:name], [:name, :id] ]
Martin M
  • 8,430
  • 2
  • 35
  • 53
  • ID doesn't work for me because the object isn't created before setting the candidate (is there a workaround?). And I was hoping to avoid publicly revealing the ID, but if this is the best solution, it beats using UUID. – Onichan Dec 19 '15 at 13:02
  • I'm using it together with `globalize` maybe that's why I do have IDs. Workaround: after_create: clear slug and save again (ugh)? – Martin M Dec 19 '15 at 13:14