You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 6 中如何将 Form Object 与 ActiveRecord 模型建立关联?

问题根因

Rails 提供的has_many等ActiveRecord关联方法,默认仅支持绑定ApplicationRecord的子类(即对应数据库表的实体模型)。Document::TranslationsForm仅混入了ActiveModel::Model,不属于ActiveRecord体系,无法被ActiveRecord关联识别,因此会抛出relation_delegate_class相关的内部方法错误。
此外当前文件路径不符合Rails自动加载规则:带Document命名空间的类需要放在对应层级的目录下,Document::TranslationsForm对应的正确路径是app/forms/document/translations_form.rb,放在根app/forms目录下会导致Rails找不到对应类,也是配置不生效的原因之一。

解决步骤

  • 移除Document模型中错误的has_many :translations_forms关联配置,手动实现Form对象的获取方法
class Document < ApplicationRecord
  # 保留原本的真实数据关联
  has_many :translations

  # 单个Form场景(适合提交单条翻译)
  def translations_form
    Document::TranslationsForm.new(document: self)
  end

  # 批量Form场景(适合每条翻译对应一个Form实例)
  def translations_forms
    translations.map { |translation| Document::TranslationsForm.new(document: self, translation: translation) }
  end
end
  • 调整TranslationsForm的文件路径与代码逻辑
    将translations_form.rb移动到app/forms/document/目录下,修改代码如下:
class Document::TranslationsForm
  include ActiveModel::Model
  # 声明表单需要的属性
  attr_accessor :document, :translation, :content, :language
  # 添加表单校验规则
  validates :content, :language, presence: true

  def save
    return false if invalid?
    # 直接通过document的真实关联创建持久化数据
    document.translations.create(content: content, language: language)
  end
end
  • 调整调用方式,不使用ActiveRecord关联语法直接操作Form实例
# 单条翻译提交场景
form = document.translations_form
form.assign_attributes(translation_params)
form.save

# 批量翻译提交场景
document.translations_forms.each_with_index do |form, index|
  form.assign_attributes(translation_params[index])
  form.save
end

补充说明

如果需要批量提交多条翻译记录,也可以在单个Form对象内接收数组参数,统一校验后一次性创建,减少重复代码:

class Document::TranslationsForm
  include ActiveModel::Model
  attr_accessor :document, :translations_list
  validates :translations_list, presence: true
  validate :validate_translations_list

  def save
    return false if invalid?
    document.translations.create!(translations_list)
    true
  end

  private
  def validate_translations_list
    translations_list.each do |item|
      next if item[:content].present? && item[:language].present?
      errors.add(:translations_list, "包含无效的翻译项")
    end
  end
end

内容的提问来源于stack exchange,提问作者Abdel P.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:36:04