基于Minitest测试Mobility Gem翻译存在性验证的问题
问题分析与解决步骤
1. 定位Name can't be blank错误根源
这个错误说明当前测试环境下,Mobility代理的name属性(对应焦点语言的翻译)为空——你在fixture里填了name: MyString,但大概率是以下原因导致验证失败:
- 测试环境默认Locale不是
en,导致name代理的是非en的翻译字段,而该字段未在fixture中填充; - Mobility的fixture加载逻辑中,
name字段默认映射的Locale与你的预期不符。
2. 快速验证Locale问题
在测试代码中临时添加Locale输出,确认当前环境的Locale:
test "validity of fixtures" do puts "Current test locale: #{I18n.locale}" # 查看输出是否为:en assert tags(:en_assigned).valid? end
3. 修复测试与Fixture
方案一:显式指定测试Locale
如果测试环境默认Locale不是en,在测试中用I18n.with_locale强制切换:
test "validity of fixtures" do I18n.with_locale(:en) do assert tags(:en_assigned).valid? end end
方案二:补全Fixture的所有Locale翻译
因为你循环验证了所有可用Locale的name_#{locale}字段的presence,所以Fixture需要填充所有对应字段。假设I18n.available_locales包含:en和:zh-CN,Fixture应改为:
en_assigned: name_en: MyString name_zh-CN: 我的标签
4. 优化Mobility验证逻辑(可选)
Mobility本身提供了多Locale验证的快捷方式,不需要手动循环生成name_#{locale}的验证规则,替换成以下代码更简洁可靠:
validates :name, presence: true, mobility: { locale: I18n.available_locales }
这会同时验证焦点语言的name属性,以及所有可用Locale的翻译存在性。
5. 修复自定义验证器的BUG
当前的translation_exists?方法没有排除当前记录本身,当更新已存在的记录时,会误判为重复。修改为:
private def translation_exists?(record, attribute) attribute_name, locale = attribute.to_s.split('_') query = record.class.joins(:string_translations).where( mobility_string_translations: { locale: locale, key: attribute_name } ) # 排除当前记录,避免更新时误判 query = query.where.not(id: record.id) if record.persisted? query.exists? end
内容的提问来源于stack exchange,提问作者Jerome
相关产品推荐
相关产品推荐

