Rails中FriendlyId的normalize_friendly_id重写后未调用怎么办
问题原因
- 你当前的配置未启用friendly_id的
:slugged模块,也没有设置独立的slug存储字段,friendly_id会直接读取code属性作为路径值,不会触发normalize_friendly_id方法——该方法仅在生成slug并写入存储字段时才会被调用。 - 你使用
after_create回调生成code字段,时机晚于friendly_id默认的slug生成时机,即使配置了slug字段,生成slug时code仍为空值。 - 你原有
generate_group_code方法存在逻辑漏洞:首次循环时code未初始化,会查询是否存在code为nil的记录,若不存在会直接将code设为nil写入数据库。
解决方案
方案1(最简实现,无需新增字段)
直接调整code生成逻辑,生成时直接输出大写,同时调整回调时机避免多余数据库查询:
class Group < ApplicationRecord include FriendlyId friendly_id :code # 调整为before_create,创建前直接赋值不需要额外update before_create :generate_group_code private def generate_group_code(size = 8) allowed_chars = ("A".."Z").to_a code = nil # 修复原有循环逻辑漏洞 loop do code = (1..size).map { allowed_chars[rand(26)] }.join break unless Group.exists?(code: code) end self.code = code end end
此时code本身就是大写格式,friendly_id直接读取该字段作为路径值,即可实现/group/ABCDEFGH的效果。
方案2(需新增slug字段,触发normalize_friendly_id)
如果你需要保留code为小写,仅路径显示大写,可新增slug字段并配置:slugged模块:
- 首先生成迁移文件新增slug字段:
# db/migrate/xxx_add_slug_to_groups.rb class AddSlugToGroups < ActiveRecord::Migration[7.0] def change add_column :groups, :slug, :string add_index :groups, :slug, unique: true end end
执行rails db:migrate同步数据库。
- 调整模型配置:
class Group < ApplicationRecord include FriendlyId # 启用slugged模块才会触发normalize逻辑,自动将生成的slug写入slug字段 friendly_id :code, use: :slugged before_create :generate_group_code private def normalize_friendly_id(value) super.upcase end def generate_group_code(size = 8) allowed_chars = ("a".."z").to_a code = nil loop do code = (1..size).map { allowed_chars[rand(26)] }.join break unless Group.exists?(code: code) end self.code = code end end
配置后friendly_id生成slug时会自动调用normalize_friendly_id将code转为大写存入slug字段,路径将直接使用大写的slug值。
补充提示
PostgreSQL默认字符串查询区分大小写,如果你需要支持用户输入小写路径也能命中对应记录,可以给code/slug字段设置大小写不敏感的唯一索引,或者在查找时统一转换大小写匹配。
内容的提问来源于stack exchange,提问作者pierre_loic
相关产品推荐
相关产品推荐

