Friendly_id 为 Rails 中的多个对象创建重复的 slug

Friendly_id creating duplicate slugs for multiple objects in Rails

我的 Rails 构建不包含路径名。该应用程序由两个主要对象组成:collectionsitems。因此,如果我有一个 link: https://foo.com/foo,这可能会标识一个集合或一个项目。上下文中的区别很明显,并且 UI 在整个应用程序中流动。

我的问题:有没有办法让 Friendly ID gem 通过查看一个 slug 是否已经被另一个对象带走来生成唯一的 slug?我知道您可以生成候选者,以便友好 ID 不会为给定对象复制一个 slug,但我需要友好 ID 来检查现有的集合 slug 和项目 slug,然后再生成一个新的 slug。

我希望这听起来不会太混乱。更简洁地重新表述:是否有一种方法可用于友好 ID 在生成新 slug 之前检查多个对象中的 slug?

注意这一切都未经测试,只是从文档中工作并阅读源代码。

您可以继承 FriendlyId::SlugGenerator class,并覆盖 available? 方法来检查现有的对手模型中的记录:

class CrossModelSlugGenerator << FriendlyId::SlugGenerator

    def available?(slug)
      if (@scope.class == "Item::ActiveRecord_Relation")
         # Search for collections with this slug and return false if they exist.
      elsif (@scope.class == "Collection::ActiveRecord_Relation")
         # Search for items with the this slug and return false if they exist.
      end

      # Otherwise do a normal slug check
      !@scope.exists_by_friendly_id?(slug)
    end

end

您可以在此处查看 SlugGenerator class 的完整代码:

https://github.com/norman/friendly_id/blob/master/lib/friendly_id/slug_generator.rb

然后您必须告诉友好 ID 配置使用那个 class。在 config/intitializers/friendly_id.rb:

中创建初始化器
FriendlyId.defaults do |config|
    config.slug_generator_class = "CrossModelSlugGenerator"
end

尝试一下,看看是否适合您。同样,我还没有测试过任何一个,但它似乎应该可行。

编辑 - 您可能需要像这样在 FriendlyId 模块中包装 class:

您可能需要在某处包含,可能在您的 class 定义中。另外,尝试将 class 包装到 FriendlyId 模块中,所以可能是这样的:

include "friendly_id"

module FriendlyId
  class CrossModelSlugGenerator << SlugGenerator
    ...
  end
end

进行此更改后,您可能还需要在配置中明确指定模块 class 名称:

FriendlyId.defaults do |config|
    config.slug_generator_class = "FriendlyId::CrossModelSlugGenerator"
end