My Page model has a slug column using FriendlyId, with the history option turned on.
I want to free slugs so that if a page with this slug is destroyed, then recreated, it can reuse the same slug.
Site.create(slug: "alpha") # => adds an entry into FriendlyId::Slug
Site.find_by(slug: "alpha").destroy # => Leaves an orphaned slug entry
Site.create(slug: "alpha") # Cannot reuse the old slug
Site.last.slug # "alpha-{uuid}"
You don't actually have to do anything.
FriendlyId's history module adds an association with the dependent: :destroy
option anyways.
module FriendlyId
module History
module Configuration
def dependent_value
dependent.nil? ? :destroy : dependent
end
end
# ....
# Configures the model instance to use the History add-on.
def self.included(model_class)
model_class.class_eval do
has_many :slugs, -> { order(id: :desc) }, **{
as: :sluggable,
dependent: @friendly_id_config.dependent_value,
class_name: Slug.to_s
}
after_save :create_slug
end
end
# ...
end
end
If you want to change it there is a configuration option. It's just not documented besides a line comment in the configuration file. You can either add it to the initializer file or pass it to the friendly_id
method.
Your "fix" is actually not doing anything except removing the ordering. Instead the issue is either a bug or just that your method of testing is flawed (it's not reproducable and destroy
can fail).
There are actual passing tests in the gem that disprove the premise of the question.
class DependentDestroyTest < TestCaseClass
include FriendlyId::Test
class FalseManual < ActiveRecord::Base
self.table_name = "manuals"
extend FriendlyId
friendly_id :name, use: :history, dependent: false
end
class DefaultManual < ActiveRecord::Base
self.table_name = "manuals"
extend FriendlyId
friendly_id :name, use: :history
end
test "should allow disabling of dependent destroy" do
transaction do
assert FriendlyId::Slug.find_by_slug("foo").nil?
l = FalseManual.create! name: "foo"
assert FriendlyId::Slug.find_by_slug("foo").present?
l.destroy
assert FriendlyId::Slug.find_by_slug("foo").present?
end
end
test "should dependently destroy by default" do
transaction do
assert FriendlyId::Slug.find_by_slug("baz").nil?
l = DefaultManual.create! name: "baz"
assert FriendlyId::Slug.find_by_slug("baz").present?
l.destroy
assert FriendlyId::Slug.find_by_slug("baz").nil?
end
end
end