友好的 ID slug 不包含 id

Friendly ID slug does not contain the id

我想要 url 这样的:

http://domain.com/products/454-table-lamp

所以我这样使用 friendly_id:

extend FriendlyId

friendly_id :slug_candidates, use: :history

def slug_candidates
  [
      [:id, :title]
  ]
end

现在,由于友好的 id 在对象被保存之前生成了 slug,所以我最终得到一个 url 像这样(请注意 URL 中缺少的 id):

http://domain.com/products/table-lamp

虽然这还不算太糟糕。一旦我保存了另一个名为 "Table Lamp" 的产品,我将得到一个 URL,如下所示:

http://domain.com/products/table-lamp-ebaf4bf5-a6fb-4824-9a07-bdda34f56973

所以我的问题是,如何确保友好 ID 也创建包含该 ID 的 slug。

好吧,简短的回答 - 你不能。 FrienlydId 在此处的 before_validation 回调中生成 slug:https://git.io/vgn89。问题是您需要在保存之前生成 slug 以避免冲突,但是您想要使用只有在实际保存之后才可用的信息,当记录已经在数据库中时。

看看这个answer for details

当然,如果你真的想要的话,你可以这样做:

def slug_candidates
  [ title, Model.maximum(:id) + 1 ]
end

但是这段代码不是线程安全的,可能会导致一些明显的问题。另一种方法 - 在保存后更改 slug,例如在 after_create 回调中。您可以将其设置为 nil 并再次调用 set_slug

但问问自己 - 你真的需要它吗?可能最好使用 created_at 中的时间戳作为 slug 候选的一部分?

只需向您的模型添加一个 after_commit 回调。在此回调中,将 slug 设置为 nil 并保存:

  after_commit :update_slug, on: :create

  def update_slug
    unless slug.include? self.id.to_s
      self.slug = nil
      self.save
    end
  end