I have three models, companies
, transactions
and subtransactions
. Each has_many of the next. I need to build a form that saves to both transactions
and multiple records of subtransactions
.
I'm struggling with the best approach to the form and the appropriate way to save to the DB. Ideally, the records get saved at once if all pass validation.
My simplified form:
<%= form_for(@transaction) do |f| %>
<div class="field" id="transaction_amount">
<%= f.label :total %><br>
<%= f.text_field :total %>
</div>
<% 1.upto(5) do |i| %>
<%= fields_for("subtransaction[#{i}]") do |s| %>
<div class="field" id="subtotal_amount">
<%= s.label :subtotal, "Subtotal #{i}" %><br>
<%= s.text_field :subtotal %>
</div>
<% end %>
<% end %>
<% end %>
My TransactionsController:
def new
@transaction = company.transactions.build if logged_in?
end
def create
@transaction = company.transactions.build(transaction_params)
params[:subtransaction].each do |i|
# build and save
end
if @transaction.save ## @subtransaction.save
flash[:success] = "Success!"
redirect_to success_url
else
render :new
end
end
The way to do this is to pass the nested
attributes through the various models:
#app/models/company.rb
class Company < ActiveRecord::Base
has_many :transactions
accepts_nested_attributes_for :transactions
end
#app/models/transaction.rb
class Transaction < ActiveRecord::Base
has_many :sub_transactions
accepts_nested_attributes_for :sub_transactions
end
This will give you the ability to use the following:
#app/controllers/transactions_controller.rb
class TransactionsController < ApplicationController
def new
@transaction = company.transactions.new
5.times do
@transaction.sub_transactions.build
end
end
def create
@transaction = company.transactions.new transaction_params
@transaction.save
end
private
def transaction_params
params.require(:transaction).permit(sub_transactions_attributes: [:subtotal])
end
end
Then...
#app/views/transactions/new.html.erb
<%= form_for @transaction do |f| %>
<%= f.fields_for :sub_transactions do |s| %>
<%= s.text_field :subtotal %>
<% end %>
<%= f.submit %>
<% end %>
This will allow you to save the various nested attributes through the main object. It is the correct, conventional, way to do it.