如何保留 PORO 表单对象字段输入?

How to retain PORO Form object field inputs?

我创建了一个 R-o-R Form 对象,它接受属性,然后将这些属性保存到一些嵌套对象中,但是,如果验证失败,输入值就会消失。反正有没有办法留住他们?

class FormObject
 include ActiveModel::Model
 attr_accessor(:name, :date)
 
 def initialize(params = {})
  @params = params
 end

 def save
  return if invalid?
  no = NestedObject.new(nested_object_params)
  no.save
 end

 def nested_object_params
  @params.permit(:name, :date)
 end
end

这是控制器

class Controller
 def new
  @form = FormObject.new
 end

 def create
  @form = FormObject.new(form_object_params)
  if @form.save
    redirect_to ...
  else
    render :new
  end
 end

 def form_object_params
  params.require(:form_object).permit(:name, :date)
 end
end

问题很可能是你在没有调用super的情况下覆盖了initialize方法。这搞乱了 ActiveModel::AttributeAssignment 完成的整个属性映射,表单真正依赖它来获取模型的属性。

class FormObject
  include ActiveModel::Model
  attr_accessor(:name, :date)
 
  def initialize(params = {})
    @params = params
    super
  end

  def save
    return if invalid?
    no = NestedObject.new(nested_object_params)
    no.save
  end

  def nested_object_params
    @params.permit(:name, :date)
  end
end

如果您使用 ActiveModel::Attributes 而不是 attr_accessor 中内置的 Ruby,您将获得类型转换,就像使用 ActiveRecord 支持的属性一样。

但这是一个直接的灾难,因为您现在拥有同一数据的三种不同表示形式:

  • FormObject 上的实例变量
  • 存储在@params中的散列
  • 存储在 NestedObject 中的属性

相反,您可能应该完全重新考虑这一点并使用委托:

class FormObject
  include ActiveModel::Model
  attr_accessor :object
  delegate :name, :name=, :date, :date=, :save, to: :object

  def intialize(**attributes)
    @object = NestedObject.new(attributes)
    super
  end
end