0

I am currently building a tool for work. It involves submitting multiple job start and end times every day. There are several jobs and each one has a new run time every day. So to speed up the process I want to submit all of the run times in one form. Currently I have all of the forms appearing but when I submit only one submission goes through. What am I missing?

runtime.rb

class Runtime < ApplicationRecord
  belongs_to :Mrpjob
  accepts_nested_attributes_for :Mrpjob
end

runtimes_controller.rb

class RuntimesController < ApplicationController
  before_action :set_runtime, only: [:show, :edit, :update, :destroy]

  # GET /runtimes
  # GET /runtimes.json
  def index
    @runtimes = Runtime.all
    @sorting = @runtimes.order("date asc")
  end

  # GET /runtimes/1
  # GET /runtimes/1.json
  def show
  end

  # GET /runtimes/new
  def new
    @runtime = Runtime.new
    @mrpjobs = Mrpjob.all
    @runtimes = Array.new(Mrpjob.count)
  end

  # GET /runtimes/1/edit
  def edit
    @mrpjobs = Mrpjob.all
  end

  # POST /runtimes
  # POST /runtimes.json
  def create
    @runtime = Runtime.new(runtime_params)


    respond_to do |format|
      if @runtime.save
        format.html { redirect_to @runtime, notice: 'Runtime was successfully created.' }
        format.json { render :show, status: :created, location: @runtime }
      else
        format.html { render :new }
        format.json { render json: @runtime.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /runtimes/1
  # PATCH/PUT /runtimes/1.json
  def update
    respond_to do |format|
      if @runtime.update(runtime_params)
        format.html { redirect_to @runtime, notice: 'Runtime was successfully updated.' }
        format.json { render :show, status: :ok, location: @runtime }
      else
        format.html { render :edit }
        format.json { render json: @runtime.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /runtimes/1
  # DELETE /runtimes/1.json
  def destroy
    @runtime.destroy
    respond_to do |format|
      format.html { redirect_to runtimes_url, notice: 'Runtime was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_runtime
      @runtime = Runtime.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def runtime_params
      params.require(:runtime).permit(:start_time, :end_time, :date, :Mrpjob_id)
    end
end

_form.html.erb

<%= form_for @runtime, :html => { :class => "form-horizontal runtime" } do |f| %>

  <% if @runtime.errors.any? %>
    <div id="error_expl" class="panel panel-danger">
      <div class="panel-heading">
        <h3 class="panel-title"><%= pluralize(@runtime.errors.count, "error") %> prohibited this runtime from being saved:</h3>
      </div>
      <div class="panel-body">
        <ul>
        <% @runtime.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
        </ul>
      </div>
    </div>
  <% end %>
  <div class="col-sm-6 padding">

    <div class="form-group">
      <%= f.label :start_time, :class => 'control-label col-lg-2' %>
      <div class="col-lg-6">
        <%= f.text_field :start_time, :class => 'form-control' %>
      </div>
      <%=f.error_span(:start_time) %>
    </div>
    <div class="form-group">
      <%= f.label :end_time, :class => 'control-label col-lg-2' %>
      <div class="col-lg-6">
        <%= f.text_field :end_time, :class => 'form-control' %>
      </div>
      <%=f.error_span(:end_time) %>
    </div>
    <div class="form-group">
      <%= f.label :date, :class => 'control-label col-lg-2' %>
      <div class="col-lg-6">
        <%= f.text_field :date, :class => 'form-control' %>
      </div>
      <%=f.error_span(:date) %>
    </div>

     <div class="row">
        <% @mrpjobs.each do |p| %>
          <div class="col-sm-2 text-center">
            <%= f.radio_button :Mrpjob_id, p.id %>
            <%= f.label :Mrpjob_id, p.name %>
          </div>
        <% end %>
    </div>

    <div class="form-group">
      <div class="col-lg-offset-2 col-lg-10">
        <%= f.submit nil, :class => 'btn btn-primary' %>
        <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                  runtimes_path, :class => 'btn btn-default' %>
      </div>
    </div>
  </div>

<% end %>

new.html.erb

<%- model_class = Runtime -%>
  <div class="page-header">
    <h1><%=t '.title', :default => [:'helpers.titles.new', 'New %{model}'], :model => model_class.model_name.human.titleize %></h1>
  </div>

  <div class="container">
    <div class="row">

        <% @runtimes.each do |runtime| %>
            <%= fields_for @runtime do |r| %>
              <%= render "form" %>
            <% end %>
        <% end %>
    </div>
  </div>
  • You may be rendering multiple forms, but you are only submitting the form whose submit button you clicked. You'll need to use ajax to submit multiple forms at the same time. Take a look at [this SO question](http://stackoverflow.com/questions/8563299/submit-multiple-forms-with-one-submit-button) – chester Jan 27 '17 at 21:56
  • Also, do you create the `@runtimes` instance variable just to have an array to iterate over to create the number of forms you need? You could just use `@mrpjobs.each do ... end `. – chester Jan 27 '17 at 22:06
  • @chester I forgot to remove it after trying a few things I had looked up. I will change that and see if I can get Ajax to work when I get home. Thank you for the help – Matthew Robertson Jan 27 '17 at 22:17
  • @chester Ok so the ajax request is working, kinda. Maybe I am doing something wrong but when I tried it with two entries it worked great. I know I am going to need at least 10 for now. When I brought it up to six to test I am not always getting them through and will end up with this error "jquery.self-bd7ddd3….js?body=1:10255 POST https://dashboard-mrmatt1877.c9users.io/runtimes 500 (Internal Server Error)". It might be a limitation on cloud 9 but I'm not sure. – Matthew Robertson Jan 27 '17 at 23:39
  • @chester I managed to get this working. The reason it wasnt working was because sqlite was locking up when trying to accept that many requests. After fiddling with it for a while I gave up and switched to postgres and it works fine now. Thank you – Matthew Robertson Jan 29 '17 at 17:05

1 Answers1

0

Ignore the comments about ajax, fields_for will do what you want and ajax for this is a wild goose chase in complexity. You just have to move the form tag to the outside of the loop.

    <% @runtimes.each do |runtime| %>
        <%= fields_for @runtime do |r| %>
          <%= render "form" %>
        <% end %>
    <% end %>

should change to be

    <% @runtimes.each do |runtime| %>
        <%= form_tag %>
          <%= fields_for @runtime do |r| %>
            <%= render "form" %>
          <% end %>
        <% end %> 
    <% end %>

And remove the form_for inside _form.html.erb. Then you'll have to create a new controller action that can handle multiple @runtime params at once, something like #update_batch.

That's not all the detail but that's the idea. What you want to happen is one form post that has the params for all of the runtimes at once.

Ehren Murdick
  • 426
  • 3
  • 8
  • I thought that would work too but when I try it the single submit button does nothing and having multiple rendered only submits the one. – Matthew Robertson Jan 29 '17 at 16:46
  • Yeah, all the fields have to be inside one form, the browser will only submit one form at a time. Also the fields have to have unique names. When you change it to use one form, what are the params that get submitted? – Ehren Murdick Jan 30 '17 at 17:23