[英]Create parent and child entry from same nested forms in Rails
EDIT 3: Just to clarify, the goal and problem is to create 2 new records from the same form of which one is the parent and one is the child. 编辑3:只是要澄清,目的和问题是要以相同的形式创建2条新记录,其中一条是父级,一条是子级。 The child needs the parent ID, but the parent is created from the same form that the child is. 子级需要父级ID,但是父级是通过与子级相同的格式创建的。
EDIT 2: I think I'm getting closer. 编辑2:我想我越来越近。 See log file at end, the deal is successfully saved and it looks like the client entry is starting to commit but then not saving. 参见末尾的日志文件,交易已成功保存,并且看起来客户条目开始提交但未保存。 Code is updated below for changes. 下面的代码已更新,以进行更改。
I followed the Railscast #196 for nested forms and I am successfully able to edit, add and delete from nested forms as long as the record is already created. 我遵循了Railscast#196的嵌套表格,只要记录已经创建,我就能够成功地从嵌套表格中进行编辑,添加和删除。 Now I am trying to use nested forms to create new records. 现在,我正在尝试使用嵌套表单来创建新记录。 I think I'm 99% of the way there, but I'm missing something I can't see anymore. 我想我已经走了99%,但是我想念的东西已经消失了。 I just need to figure out how to pass the id
of the parent to the child. 我只需要弄清楚如何将父母的id
传递给孩子。
In addition to the Railscast I used this answer to set inverse_of
relationships and call the save order (using create
instead of save
though). 除了Railscast之外,我还使用此答案来设置inverse_of
关系并调用保存顺序(尽管使用create
而不是save
)。 I'm pretty sure the problem is in the form or the controller (but models are listed below too) 我很确定问题出在表单或控制器上(但型号也在下面列出)
Nested Form (I tried to simplify to make it easier to read) 嵌套表格(我尝试简化以使其更易于阅读)
EDIT 2: remove hidden field 编辑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 %>
Controller 调节器
EDIT 2: include deal_id param & change save calls 编辑2:包括deal_id参数和更改保存调用
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
EDIT 2: No longer yields errors in browser and success flash message is triggered 编辑2:不再在浏览器中产生错误,并触发成功刷新消息
EDIT 2: Here is the console output on submit (the record is saved and can be viewed it just doesn't have a client) 编辑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
Users 用户
class User < ApplicationRecord
has_many :deals
end
Deals 交易
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
Clients 客户端
class Client < ApplicationRecord
belongs_to :deal, inverse_of: :clients
validates :name, presence: true
validates :deal_id, presence: true
end
You are missing the deal_id on the params 您缺少参数上的deal_id
def deal_params
params.require(:deal).permit(:headline, :matter, :summary, clients_attributes: [:id, :deal_id, :name, :_destroy])
end
and on the create of deal, you can make something like this 在创建交易时,您可以进行如下操作
def create
@deal = Deal.new(deal_params)
if @deal.save
...
and just add a hidden field on the form for the user_id parameter. 并仅在表单上为user_id参数添加一个隐藏字段。
The problem is the validations in the client model. 问题在于客户端模型中的验证。 Removing the validations will allow the records to be correctly saved from the nested form. 删除验证将允许从嵌套表单中正确保存记录。
In the Client model remove the name and deal_id validators 在客户端模型中,删除名称和deal_id验证程序
class Client < ApplicationRecord belongs_to :deal, inverse_of: :clients end
In the controller add build
to the new
action so it's nicer for the users: 在控制器中,将build
添加到new
操作中,以便对用户更好:
def new @deal = Deal.new @client = @deal.clients.build end
.build
is not strictly necessary since the helper method that was created from the Rails Cast will create new client entries on demand, but with it the user is presented with the placeholder first entry which is ignored if blank. .build
并不是绝对必要的,因为从Rails Cast创建的帮助程序方法将根据需要创建新的客户端条目,但是使用它,将为用户显示占位符第一个条目,如果为空白,则将忽略该条目。
To keep empty client records from saving I added a reject_if: proc
to the deal model 为了避免保存空的客户记录,我在交易模型中添加了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
I'll leave this open/unanswered in case someone can explain better why my solution worked and if there's a better way to do it. 如果有人可以更好地解释我的解决方案为什么起作用以及是否有更好的方法,我将保留此公开/未答复的状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.