【问题标题】:Ruby on Rails - Multiple Models FormRuby on Rails - 多模型表单
【发布时间】:2014-06-30 01:52:40
【问题描述】:

我有 5 个模型,我需要创建一个可以为每个模型创建一个新对象的唯一表单。模型是

Contract.rb
    belongs_to :establishment

Establishment.rb
    has_many :contracts
    belongs_to :address
    belongs_to :client

Address.rb
    has_many :establishments
    belongs_to :zip

Client.rb
    has_many :establishments

Zip.rb
    has_many :addresses

将创建对象的表单是Contract的表单

我的第一种方法是为其他模型创建 fields_for each,例如:

_form.html.erb

<%= form_for(@contract) do |f| %>
<% if @contract.errors.any? %>
<div id="error_explanation">
  <h2><%= pluralize(@contract.errors.count, "error") %> prohibited this contract from being saved:</h2>
...#fields for contract
<%= f.fields_for @client do |client|%>
  <%=client.label 'Name'%><%=client.text_field :name%>
  ...#other fields for client
<%= f.fields_for @address do |address|%>
  <%=address.label 'Street'%><%=address.text_field :street%>
  ...#other fields for address
<%=f.fields_for @zip do |zip|%>
  <%=zip.label 'Code'%><%=zip.number_field :code%>
  ...#other fields for zip

表单运行良好,并且正在获取所有字段,但在ContractController.rb 上,我无法访问参数上的地址、客户和邮编字段。如果我使用@client = Client.create(params[:client]),它不会出错,但不会在模型上创建对象。我意识到params[:client](以及其他不用于合同的参数是 NIL)。然后我使用了params[:contract][:client],我得到了错误ForbiddenAttributesError...

所以,我决定改变方法并开始考虑多级嵌套属性,但我仍然没有得到......

我已将模型更改为:

Contract.rb
    belongs_to :establishment
    accepts_nested_attributes_for :establishment

    has_one :address, through: :establishment
    accepts_nested_attributes_for :address

    has_one :zip, through: :address
    accepts_nested_attributes_for :zip

    has_one :client, :through => :establishment
    accepts_nested_attributes_for :client

在控制器上我已经完成了

ContractController.rb

def new
  @contract = Contract.new
  @establishment = @contract.build_establishment
  @address = @establishment.build_address
  @zip = @address.build_zip
  @client = @establishment.build_client
end

但现在表单没有Client, Address and Zip 的字段

是否可以创建这种类型的表单?

【问题讨论】:

  • 尝试将fields_for @client更改为fields_for :client

标签: ruby-on-rails forms nested


【解决方案1】:

如果你打算使用accepts_nested_attributes_for,请记住API

“嵌套属性允许您通过父级将属性保存在关联记录上”

所以,这样说是无效的:

Class Contract #child class 
   belongs_to :establishment
   accepts_nested_attributes_for :establishment

因为Contractchild。不是Parent

正确的做法是:

Class Establishment # parent class
    has_many :contracts
    accepts_nested_attributes_for :contracts

然后在您的Establishments 控制器params 中,您将添加:

contracts_attributes: [:id, attribute1, attribute2] # 别忘了加:id

对所有其他模型执行相同的方法。阅读API中的示例

【讨论】:

  • 好的,请记住,是否可以创建这种类型的表单?模型在哪里是孩子或无关的?我很难相信 ruby​​ on rails 无法完成这项工作......
  • 我不确定您是否可以从一个表单更新所有 5 个模型。但是您可以将某些表单嵌套在一起。 Cocoon gem 会帮助你。它有很好的示例文档。
【解决方案2】:

---编辑的答案---- 删除了 [:contract][:client_attributes][:...] 处的 _attributes(以及 :zip 和 :address)

GB几乎得到它,但还不够。
回到第一种方法,看完这篇article我做了如下改动:

Contract
_form.html.erb

  <%= form_for(@contract) do |f| %>
  <% if @contract.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@contract.errors.count, "error") %> prohibited this contract from                   being saved:</h2>
  ...#fields for contract
  <%= f.fields_for :client, @client do |client|%>
    <%=client.label 'Name'%><%=client.text_field :name%>
    ...#other fields for client
  <%= f.fields_for :address, @address do |address|%>
    <%=address.label 'Street'%><%=address.text_field :street%>
    ...#other fields for address
  <%=f.fields_for :zip, @zip do |zip|%>
    <%=zip.label 'Code'%><%=zip.number_field :code%>
    ...#other fields for zip

因此,必须是 f.fields_for :client, @client do |client|(地址和 zip 相同),而不是 f.fields_for @client do |client|

ContractController

def new
  @contract = Contract.new
  @client = Client.new
  @address = Address.new
  @zip = Zip.new
end

def create
  @contract = Contract.new(contract_params)

  if !Zip.exists?(:cod_postal1 => params[:contract][:zip][:cod_postal1], :cod_postal2 => params[:contract][:zip][:cod_postal2])
    create_zip
  elsif
    @zip = Zip.where(:cod_postal1 => params[:contract][:zip][:cod_postal1], :cod_postal2 => params[:contract][:zip][:cod_postal2])
  end

  create_client
  create_address
  @address.zip = @zip
  @establishment = Establishment.new(:sede => true)
  @establishment.address = @address
  @establishment.client = @client
  @client.save
  @address.save
  @establishment.save
  @contract.establishment = @establishment

  respond_to do |format|
    if @contract.save
    ...
end

def create_client
  @client = Client.create(
                          :numero => params[:contract][:client][:numero],
                          ...#other client fields
                         )
end

def create_zip
  @zip = Zip.create(
                    :distrito => params[:contract][:zip][:distrito],
                    :concelho => params[:contract][:zip][:concelho],
                    ...#other zip fields
  )      
end

def create_address
  @address = Address.create(
                            :rua => params[:contract][:address][:rua],
                            ...#other address fields
  )
end

这就是诀窍。在一个带有一个提交按钮的表单中,创建了 5 个不同的模型

【讨论】:

    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多