简体   繁体   English

在Rails中从相同的嵌套表单创建父项和子项

[英]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. 删除验证将允许从嵌套表单中正确保存记录。

  1. In the Client model remove the name and deal_id validators 在客户端模型中,删除名称和deal_id验证程序

     class Client < ApplicationRecord belongs_to :deal, inverse_of: :clients end 
  2. In the controller add build to the new action so it's nicer for the users: 在控制器中,将build添加到new操作中,以便对用户更好:

  3.  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创建的帮助程序方法将根据需要创建新的客户端条目,但是使用它,将为用户显示占位符第一个条目,如果为空白,则将忽略该条目。

  1. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM