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. The child needs the parent ID, but the parent is created from the same form that the child is.
EDIT 2: I think I'm getting closer. 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. 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. I just need to figure out how to pass the id
of the parent to the child.
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). 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
<%= 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
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
EDIT 2: Here is the console output on submit (the record is saved and can be viewed it just doesn't have a client)
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