如果字段名称相同,如何在 Rails 中使用嵌套表单?

How to use nested forms in Rails if the fields have the same name?

我有两个模型,狗和主人,我希望他们的名字相同,如果我要求填写两次字段(一次是狗,另一次是主人),那将是多余的。我想知道是否有一种更简单的方法可以通过一个输入更新两个数据库。

<h1>Create a new Dog:</h1>
<%= form_for(@dog) do |f|%>
  <div>
    <%= f.label :name%>
    <%= f.text_field :name%>
  </div><br>
    
  <div>
    <%= f.label :breed%>
    <%= f.text_field :breed%>
  </div><br>
    
  <div>
    <%= f.label :age%>
    <%= f.text_field :age%>
  </div><br>
    
  <div>
    <h3>create a new owner:</h3>
    <%= f.fields_for :owner, Owner.new do |owner_attributes|%>
        <%= owner_attributes.label :name, "Owner Name:" %>
        <%= owner_attributes.text_field :name %>
    <% end %>
  </div>
    
  <%= f.submit %>
    
<% end %>

首先,不知道为什么要让主人和狗的名字保持一致。

但是,有很多方法可以实现您想要的:

  1. 您可以简单地从表单中省略所有者姓名。

所以你不再需要:<%= owner_attributes.label :name, "Owner Name:" %> 或者您不再需要:

<div>
    <%= f.label :name%>
    <%= f.text_field :name%>
  </div><br>

并且在 Owner/Dog 模型中,您可以在回调中传递 dog/owner 的名称 - 可能是 after_initialize 或 before_save 或 before_validation 取决于根据您的验证要求。

class Dog
  belongs_to :owner
  before_validation :set_name

  private

  def set_name
    self.name = owner&.name
  end
end
  1. 您可以将主人的名字改为隐藏字段,并可以写一些 javascript 以在提交表单或 onblur 事件之前用狗的名字更新隐藏字段。我更喜欢第一种方法,因为它比仅用 JS 解决方案来维护数据库一致性更简单、更安全

如果狗belongs_to和主人,你真的不需要单独存储主人的名字。您可以在任何有 Dog 实例的地方调用 dog.owner.name。话虽如此,使用 .merge():

在控制器中的 POSTed 表单值之上附加属性相对简单
def create
  @dog = Dog.new(dog_params.merge(owner: params[:dog][:owner])[:name])
  if @dog.save
    ...
  end
end

def dog_params
  params.require(:dog).permit(:name, :breed, :age, owner: %i[name])
end