使用 chinese_pinyin + friendly_id 为中文标题生成 slug

来源:互联网 时间:1970-01-01


在许多项目中,我们可能都会遇到需要为数据生成 slug 的场景,这些场景类似于:

基于商品名称生成 slug 基于文章标题生成 slug

至于为什么需要生成 slug,而不是使用比如 Rails 中默认自增的主键也就是数据的 id,原因其实很简单:

使用自增 id 容易暴露数据,比如通过订单 id 可能导致遍历所有订单,不信,你看这里就有个 例子 增加 URL 友好性,/products/18376 这样的链接肯定没有比 /products/apple-watch-gold 这样的链接更招人喜欢 friendly_id

friendly_id 是用来生成 slug 的 ruby gem,假设我们有一个产品模型 Product,使用 friendly_id 为商品名称( name)生成 slug 的示例代码如下:

class Product < ActiveRecord::Base friendly_id :name, use: :sluggedend

上面的代码理论上来说已经完成我们所需要的工作了,但是如果 title 包含中文的话,生成的 slug 就有点类似 30f175f4-1e56-4e3a-823d-a7c1a5d32b29这样的乱码了,实际上这个 slug 对应的原来的 title 是 测试产品。这样的 slug 虽然避免了自增 id 的弊端,但是却丧失了友好性。如果 slug 能够基于汉语拼音生成,岂不更好?

自己控制 slug 生成方式

阅读 friendly_id 的源码可以找到以下代码:

module FriendlyId module Slugged # ... def normalize_friendly_id(value) value.to_s.parameterize end # ... endend

这段代码便是 friendly_id 基于输入生成 slug 的核心代码,使用 ActiveSupport 扩展后的 String类的 parameterize 方法,此方法会将除了英文字母、数字、短横线以及下划线之外的字符转换为 -,所以不适用于中文的情况,我们需要 重写该方法,以满足我们的需求。

中文拼音利器—— chinese_pinyin

中文生成中文拼音的工具,我选择了黄志敏先生写的 chinese_pinyin这个 gem,推荐理由就是简单够用。

以下是单独使用这个 gem 时的示例:

2.2.0 :009 > Pinyin.t("中国人") => "zhong guo ren"2.2.0 :010 > Pinyin.t("Hello, 李雷") => "Hello li lei" 组装!!!

根据 friendly_id 的注释,如果你只需要为单独一个 model 定制 slug 的生成逻辑,那么建议你只在相关的 model 中定义同名方法即可。但是由于我是需要为多个 model 定制中文的 slug 生成逻辑,所以我选择了直接重定义 FriendlyId::Slugged模块中的这个方法:

# config/initializers/friendly_id/slugged.rbmodule FriendlyId module Slugged # 重定义 friendly_id 方法,实现 slug 从中文到拼音,非中文不受影响 def normalize_friendly_id(value) Pinyin.t(value.to_s).parameterize end endend

这样的定义方式使得新的 normalize_friendly_id方法对所有依赖 friendly_id 的代码都生效。

最后通过新的方法为我们的产品生成新的 slug,现在“测试产品”得到的 slug 变为 ce-shi-chan-pin了:

product.update(slug: nil) # 显式清空 slug, friendly_id 在 save 时会自动重新生成 slug

最后产品的链接已变为 /products/ce-shi-chan-pin,比起 /products/30f175f4-1e56-4e3a-823d-a7c1a5d32b29,可真是叫人心旷神怡。



相关阅读:
Top