编辑3:为了澄清,目标和问题是从同一形式创建2条新记录,其中一条是父母,一条是孩子。子项需要父ID,但父项是从子项的相同表单创建的。
编辑2:我想我越来越近了。最后查看日志文件,交易成功保存,看起来客户端条目开始提交但后来没有保存。代码在下面更新以进行更改。
我跟随Railscast #196嵌套表单,只要已经创建了记录,我就能成功编辑,添加和删除嵌套表单。现在我尝试使用嵌套表单来创建新记录。我想我99%的路上都有,但我错过了一些我无法再看到的东西了。我只需要弄清楚如何将父母的id
传递给孩子。
除了Railscast之外,我使用this answer来设置inverse_of
关系并调用保存顺序(尽管使用create
而不是save
)。我很确定问题出在表格或控制器中(但模型也在下面列出)
嵌套表格(我试图简化以便于阅读)
编辑2:删除隐藏字段
<%= form_for(@deal) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="deal-<%= @deal.id %>" >
<div class="form-group">
<%= f.label :headline %>
<%= f.text_field :headline, required: true, placeholder: "Headline" %>
</div>
<div class="form-group" id="clients">
<%= f.fields_for :clients do |client_form| %>
<div class="field">
<%= client_form.label :client %><br />
<%= client_form.text_field :name, placeholder: "Client name" %>
</div>
<% end %>
<%= link_to_add_fields "Add client", f, :clients %>
</div>
<div class="form-group">
<%= f.label :matter %>
<%= f.text_field :matter, placeholder: "Matter", rows: "4" %>
</div>
<div class="form-group">
<%= f.label :summary %>
<%= f.text_area :summary, placeholder: "Deal summary", rows: "4" %>
</div>
<div class="form-group">
<div class="action-area">
<%= f.submit "Add deal" %>
</div>
</div>
</div>
<% end %>
控制器
编辑2:包括deal_id param&amp;更改保存电话
class DealsController < ApplicationController
before_action :require_login
def new
@deal = Deal.new
@client = @deal.clients
end
def create
@deal = current_user.deals.create(deal_params)
if @deal.save
flash[:success] = "Your deal was created!"
redirect_to root_url
else
render 'deals/new'
end
end
private
def deal_params
params.require(:deal).permit(:headline, :matter, :summary, clients_attributes: [:id, :deal_id, :name, :_destroy])
end
end
编辑2:不再在浏览器中产生错误并触发成功闪存消息
编辑2:这是提交时的控制台输出(记录已保存,可以查看它只是没有客户端)
Started POST "/deals" for ::1 at 2017-04-26 00:13:08 +0200
Processing by DealsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"hbvpS6KsZOorR3u4LgNoG5WHgerok6j3yYzO+dFUHs9thsxRi+rbUkm88nb7A5WvlmWZEcvaDvCKywufP3340w==", "deal"=>{"headline"=>"headline", "client"=>{"name"=>"aaa"}, "matter"=>"", "summary"=>""}, "commit"=>"Add deal"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: client
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "deals" ("headline", "matter", "summary", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["headline", "headline"], ["matter", ""], ["summary", ""], ["user_id", 1], ["created_at", 2017-04-25 22:13:08 UTC], ["updated_at", 2017-04-25 22:13:08 UTC]]
(3.8ms) commit transaction
(0.1ms) begin transaction
(0.1ms) commit transaction
Redirected to http://localhost:3000/
Completed 302 Found in 16ms (ActiveRecord: 4.6ms)
Models for reference
用户
class User < ApplicationRecord
has_many :deals
end
优惠
class Deal < ApplicationRecord
belongs_to :user
has_many :clients, inverse_of: :deal
validates :headline, presence: true
accepts_nested_attributes_for :clients, allow_destroy: true
end
客户
class Client < ApplicationRecord
belongs_to :deal, inverse_of: :clients
validates :name, presence: true
validates :deal_id, presence: true
end
答案 0 :(得分:0)
你错过了参数上的deal_id
def deal_params
params.require(:deal).permit(:headline, :matter, :summary, clients_attributes: [:id, :deal_id, :name, :_destroy])
end
并且在创造交易时,你可以做出像这样的事情
def create
@deal = Deal.new(deal_params)
if @deal.save
...
只需在表单上为user_id参数添加隐藏字段。
答案 1 :(得分:0)
问题是客户端模型中的验证。删除验证将允许从嵌套表单中正确保存记录。
在客户端模型中删除名称和deal_id验证器
class Client < ApplicationRecord
belongs_to :deal, inverse_of: :clients
end
在控制器中将build
添加到new
操作,以便为用户提供更好的信息:
def new
@deal = Deal.new
@client = @deal.clients.build
end
.build
并不是绝对必要的,因为从Rails Cast创建的辅助方法将按需创建新的客户端条目,但是使用它时,将向用户显示占位符第一个条目,如果为空,则忽略该条目。 / p>
为了保持空客户端记录不被保存,我在交易模型中添加了reject_if: proc
class Deal < ApplicationRecord
belongs_to :user
has_many :clients, inverse_of: :deal
validates :headline, presence: true
accepts_nested_attributes_for :clients, allow_destroy: true, reject_if: proc { |attributes| attributes['name'].blank? }
end
如果有人可以更好地解释为什么我的解决方案有效,以及是否有更好的方法可以解决这个问题,我会将此问题保持开放/未答复。