关联模型属性变更时如何更新Attraction的slug?
关联模型变更时同步Friendly ID Slug问题解决
问题背景
现有Attraction和Venue两个模型,关联关系与Friendly ID配置如下:
# Attraction模型 class Attraction < ApplicationRecord belongs_to :venue friendly_id :slugged_name_and_venue, use: :slugged end
# Venue模型 class Venue < ApplicationRecord has_many :attractions, dependent: :nullify friendly_id :slugged_name_and_location, use: :slugged end
Attraction的slug依赖关联Venue的name和location_1属性,当这两个属性变更时,Attraction的slug无法自动同步更新。(注:已知此设计不符合slug稳定的常规用法,但业务场景必须如此)
此前尝试的方案未生效,核心原因是Venue更新完成后,其变更记录已被重置,Attraction无法检测到关联模型的属性变化。
解决方案
修改Venue模型
在Venue的更新回调中,直接强制关联的Attraction重新生成并保存slug:
class Venue < ApplicationRecord has_many :attractions, dependent: :nullify friendly_id :slugged_name_and_location, use: :slugged def should_generate_new_friendly_id? slug.blank? || name_changed? || location_1_changed? end # 当name或location_1变更后,同步更新关联Attraction的slug after_update :sync_attraction_slugs, if: -> { saved_change_to_name? || saved_change_to_location_1? } private def sync_attraction_slugs attractions.find_each do |attraction| # 强制触发slug生成逻辑 attraction.send(:generate_friendly_id) # 保存更新后的slug,若需要模型验证可去掉validate: false attraction.save(validate: false) end end end
简化Attraction模型的slug生成判断
调整should_generate_new_friendly_id?方法,确保在自身属性变更或关联Venue未完成更新时也能触发slug生成:
class Attraction < ApplicationRecord belongs_to :venue friendly_id :slugged_name_and_venue, use: :slugged def should_generate_new_friendly_id? slug.blank? || name_changed? || full_name_changed? || venue_id_changed? || (venue.present? && (venue.name_changed? || venue.location_1_changed?)) end end
原理说明
- 此前方案失效是因为Venue更新完成后,
saved_change_to_*会返回false,Attraction无法检测到关联模型的变更;现在直接在Venue的回调中主动触发Attraction的slug生成逻辑,绕过属性变更检测的限制。 - 使用Friendly ID内部的
generate_friendly_id方法强制重新计算slug,确保生成的slug包含Venue最新的属性值。
内容的提问来源于stack exchange,提问作者rctneil
相关产品推荐
相关产品推荐

