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

时间:2017-04-25 10:50:14

标签: ruby-on-rails forms nested-forms

编辑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

2 个答案:

答案 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)

问题是客户端模型中的验证。删除验证将允许从嵌套表单中正确保存记录。

  1. 在客户端模型中删除名称和deal_id验证器

    class Client < ApplicationRecord
      belongs_to :deal, inverse_of: :clients
    end
    
  2. 在控制器中将build添加到new操作,以便为用户提供更好的信息:

  3. def new
      @deal = Deal.new
      @client = @deal.clients.build
    end
    
  4. .build并不是绝对必要的,因为从Rails Cast创建的辅助方法将按需创建新的客户端条目,但是使用它时,将向用户显示占位符第一个条目,如果为空,则忽略该条目。 / p>

    1. 为了保持空客户端记录不被保存,我在交易模型中添加了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
      
    2. 如果有人可以更好地解释为什么我的解决方案有效,以及是否有更好的方法可以解决这个问题,我会将此问题保持开放/未答复。