Đỗ Tiến Đỗ Tiến - 4 months ago 38
Ruby Question

Submit multiple forms in rails

currently I am adding a new feature for my application which is allowing the user to submit many forms of the same object with one submit button.

I've just added the 'add_inquery' button that when a user clicks on it, a new form will be rendered(in the same page). I don't limit the numbers of the forms that the users want to submit. Generally, they can submit from 10 to 20 forms if they want.

The error I get is:


undefined method `fields_for' for nil:NilClass


Here are all of my codes:

_form.html.haml:

.col-md-3
= link_to "Add Inquery", pricing_histories_add_inquery_path, remote: true, class: 'btn btn-default', data: {disable_with: "Please wait..."}

= form_tag pricing_histories_path , html: {class: 'form-horizontal'} do |f|
%div.alert.alert-danger.display-hide
%button.close{'data-close' => 'alert'}
You have some form errors. Please check below.
%div.alert.alert-success.display-hide
%button.close{'data-close' => 'alert'}
Your form validation is successful!
%div.row
%div.col-xs-12.form-body
= f.fields_for '' do |fd|
= render 'form_body', f: fd, object: f.object
%div.form-actions
%div.row
%div.col-md-offset-9.col-md-3
%button.btn.green{:type => 'submit'} Submit


_form_body.html.haml:

%div.form-group.form-md-line-input
%label.control-label.col-md-3
= I18n.t('columns.customer_name')
%span.required *
%div.col-md-6
= f.text_field_tag :customer_name, placeholder: 'Customer Name', class: 'form-control'
%div.form-control-focus
%span.help-block Enter Customer Name
%div.form-group.form-md-line-input
%label.control-label.col-md-3
= I18n.t('columns.actual_customer')
%span.required *
%div.col-md-6
= f.text_field_tag :actual_customer, placeholder: 'Actual Customer', class: 'form-control actual_customer'
%div.form-control-focus
%span.help-block Enter Actual Customer
%div.form-group.form-md-line-input
%label.control-label.col-md-3
= I18n.t('columns.bco')
%span.required *
.col-md-6
.mt-radio-inline
%label.mt-radio
= f.radio_button :bco, true, :checked => true, class: 'bco'
= I18n.t('columns.bco_splited')
%span
%label.mt-radio
= f.radio_button :bco, false, class: 'non_bco'
= I18n.t('columns.non_bco_splited')
%span
%div.form-group.form-md-line-input
= f.label :trade_id, class: 'col-md-3 control-label' do
= I18n.t('columns.trade')
%span.required *
%div.col-md-6
= f.select :trade_id, options_for_select(Trade.all.map{|l| [l.name + '(' + l.code + ')', l.id]}, object.trade_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Trade
%div.form-group.form-md-line-input
= f.label :trade_id, class: 'col-md-3 control-label' do
= I18n.t('columns.sub_trade')
%span.required *
%div.col-md-6
= f.select :sub_trade_id, options_for_select(SubTrade.all.map{|l| [l.name + '(' + l.code + ')', l.id]}, object.trade_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Sub Trade
%div.form-group.form-md-line-input
= f.label :bound, class: 'col-md-3 control-label' do
= I18n.t('columns.bound')
%span.required *
.col-md-6
= f.select :bound, PricingHistory.get_bound_array,
{}, {class: 'form-control select2_category'}
%div.form-control-focus
%span.help-block Enter Bound
%div.form-group.form-md-line-input
= f.label :sales_week_id, class: 'col-md-3 control-label' do
Sales Week
%span.required *
%div.col-md-6
= f.select :sales_week_id, options_for_select(SalesWeek.all.map{|sw| [sw.display, sw.id]}, object.sales_week_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Sales Week
%div.form-group.form-md-line-input
= f.label :origin_location_id, class: 'col-md-3 control-label' do
Origin Location
%span.required *
%div.col-md-6
= f.select :origin_location_id, options_for_select(Location.all.map{|l| [l.name + '(' + l.code + ')', l.id]}, object.origin_location_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Origin Location
%div.form-group.form-md-line-input
= f.label :destination_location_id, class: 'col-md-3 control-label' do
Destination Location
%span.required *
%div.col-md-6
= f.select :destination_location_id, options_for_select(Location.all.map{|l| [l.name + '(' + l.code + ')', l.id]}, object.destination_location_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Destination Location
%div.form-group.form-md-line-input
= f.label :surcharge_group_id, class: 'col-md-3 control-label' do
Surcharge Group
%span.required *
%div.col-md-6
= f.select :surcharge_group_id, options_for_select(SurchargeGroup.all.map{|s| [s.code, s.id]}, object.surcharge_group_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Surcharge Group Code
%div.form-group.form-md-line-input
= f.label :commodity_group_id, class: 'col-md-3 control-label' do
Commodity Group
%span.required *
%div.col-md-6
= f.select :commodity_group_id, options_for_select(CommodityGroup.all.map{|s| [s.name + '(' + s.code + ')', s.id]}, object.surcharge_group_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Commodity Group
%div.form-group.form-md-line-input
= f.label :tier_id, class: 'col-md-3 control-label' do
Tier
%span.required *
%div.col-md-6
= f.select :tier_id, options_for_select(Tier.all.map{|s| [s.tier, s.id]}, object.tier_id), {}, {class: 'form-control'}
%div.form-control-focus
%span.help-block Enter Tier
%div.form-group.form-md-line-input
= f.label :d2_volume, class: 'col-md-3 control-label' do
D2 Volume
%span.required *
%div.col-md-6
= f.number_field :d2_volume, class: 'form-control', 'aria-required' => true, 'aria-describedby' => 'number-error'
%div.form-control-focus
%span.help-block Enter D2 Volume
%div.form-group.form-md-line-input
= f.label :d4_volume, class: 'col-md-3 control-label' do
D4 Volume
%span.required *
%div.col-md-6
= f.number_field :d4_volume, class: 'form-control', 'aria-required' => true, 'aria-describedby' => 'number-error'
%div.form-control-focus
%span.help-block Enter D4 Volume
%div.form-group.form-md-line-input
= f.label :d5_volume, class: 'col-md-3 control-label' do
D5 Volume
%span.required *
%div.col-md-6
= f.number_field :d5_volume, class: 'form-control', 'aria-required' => true, 'aria-describedby' => 'number-error'
%div.form-control-focus
%span.help-block Enter D5 Volume
%div.form-group.form-md-line-input
= f.label :d7_volume, class: 'col-md-3 control-label' do
D7 Volume
%span.required *
%div.col-md-6
= f.number_field :d7_volume, class: 'form-control', 'aria-required' => true, 'aria-describedby' => 'number-error'
%div.form-control-focus
%span.help-block Enter D7 Volume
%div.form-group.form-md-line-input
= f.label :r2_volume, class: 'col-md-3 control-label' do
R2 Volume
%span.required *
%div.col-md-6
= f.number_field :r2_volume, class: 'form-control', 'aria-required' => true, 'aria-describedby' => 'number-error'
%div.form-control-focus
%span.help-block Enter R2 Volume
%div.form-group.form-md-line-input
= f.label :r5_volume, class: 'col-md-3 control-label' do
R5 Volume
%span.required *
%div.col-md-6
= f.text_field_tag :r5_volume, class: 'form-control', 'aria-required' => true, 'aria-describedby' => 'number-error'
%div.form-control-focus
%span.help-block Enter R5 Volume


pricing_history_controller.rb:

class PricingHistoriesController < ApplicationController
before_action :set_pricing_history, only: [:show, :edit, :update, :destroy]

def add_inquery

end

def index
@pricing_histories = current_user.pricing_histories.all.order(updated_at: :desc)
end

def show
end

def new
@pricing_history = current_user.pricing_histories.build
@pricing_histories = []
6.times do
@pricing_histories << @pricing_history
end
end

def edit
end

def create
params["pricing_history"].each do |pricing_history|
pricing_history = current_user.pricing_histories.build(pricing_history_params(pricing_history))
pricing_history.tier_id = 3
customer_name = pricing_history.customer_name

if pricing_history.bco == false && Scra.exists?(actual_customer: pricing_history.actual_customer)
return redirect_to new_pricing_history_path, notice: init_message(:error, t('scras.record_exist'))
end

if (scra = Scra.find_by_customer_name(customer_name)).present?
pricing_history.tier_id = Tier.find_by_scra_id(scra.id).id
end

if pricing_history.save
# pricing_history.calculate!
# redirect_to pricing_histories_path, notice: init_message(:success, t('message.new_success', page_name: t('page_name.pricing_history')))
else
render :new
end
end
# @pricing_history = current_user.pricing_histories.build(pricing_history_params)
# @pricing_history.tier_id = 3
# customer_name = @pricing_history.customer_name
#
# if @pricing_history.bco == false && Scra.exists?(actual_customer: @pricing_history.actual_customer)
# return redirect_to new_pricing_history_path, notice: init_message(:error, t('scras.record_exist'))
# end
#
# if (scra = Scra.find_by_customer_name(customer_name)).present?
# @pricing_history.tier_id = Tier.find_by_scra_id(scra.id).id
# end
#
# if @pricing_history.save
# @pricing_history.calculate!
# redirect_to @pricing_history, notice: init_message(:success, t('message.new_success', page_name: t('page_name.pricing_history')))
# else
# render :new
# end
end

def update
if @pricing_history.update(pricing_history_params)
if Scra.exists?(customer_name: @pricing_history.customer_name)
@pricing_history.update_columns(tier_id: 3)
end
redirect_to @pricing_history, notice: init_message(:success, t('message.update_success', page_name: t('page_name.price_history')))
else
render :edit
end
end

def destroy
@pricing_history.destroy
redirect_to pricing_histories_url, notice: init_message(:success, t('message.delete_success', page_name: t('page_name.price_history')))
end

private
def set_pricing_history
@pricing_history = PricingHistory.find(params[:id])
end

def pricing_history_params(element_params)
element_params.permit(
:sales_week_id,
:trade_id,
:sub_trade_id,
:bound,
:origin_location_id,
:destination_location_id,
:surcharge_group_id,
:commodity_group_id,
:tier_id,
:customer_name,
:actual_customer,
:bco,
:d2_volume,
:d4_volume,
:d5_volume,
:d7_volume,
:r2_volume,
:r5_volume
)
end
end

Answer

You are calling f.fields_for inside a form_tag defined form. To use the f.fields_for you need to have a defined model using form_for.

If you wish to use fields_for without using form_for, try removing the f. at the beginning and just use:

fields_for '' do |fd|
Comments