Home > database >  Ruby 2.7.0 on Rails 6.1, 2 separate post forms one view
Ruby 2.7.0 on Rails 6.1, 2 separate post forms one view

Time:09-23

hope your having a wonderful day drinking some coffee and responding to some forms. Problem: As my title states, I am trying to create 2 forms on one view. I am new to ruby on rails.

My controller functions: Controller name is border_rotation:

def create
    if params[:export_submit]
      @border_rotation_export = BorderRotationExport.new(border_rotation_export_params)
      respond_to do |format|
        if @border_rotation_export.save
          flash[:success] = "Export successfully created"
          format.html { render :new }
          else
          flash[:error] = "Export was not created."
        end
      end
    else
      @border_rotation_import = BorderRotationImport.new(border_rotation_import_params)
      respond_to do |format|
        if @border_rotation_import.save
          flash[:success] = "Export successfully created"
          format.html { render :new }
          else
          flash[:error] = "Export was not created."
        end
      end
    end
  end 

  def new
    @border_rotation_export = BorderRotationExport.new
    @border_rotation_import = BorderRotationImport.new
  end

private 
  def border_rotation_export_params
    params.require(:border_rotation_export).permit(:exporter_name,:vehicle_color,:rot_num,:current_date,:current_time,:goods_description,:license_num,:entry)
  end

  def border_rotation_import_params
    params.require(:border_rotation_import).permit(:importer_name,:vehicle_color,:rot_num,:current_date,:current_time,:goods_description,:license_num,:entry)
  end 

My new View form: It has 2 forms and is enclosed in bootstrap tabs

<%=  form_for @border_rotation_export, url: rotation_create_path, method: :post do |f|%>
<lable>Importer Name: </lable><%= f.text_field :importer_name, class: "form-control", placeholder: "Importer Name"%>
<lable>Vehicle Color: </lable><%= f.text_field :vehicle_color, class: "form-control", placeholder: "Vehicle Color"%>
**its fields**
<% end %> 

and

<%=  form_for @border_rotation_import, url: rotation_create_path, method: :post do |f|%>
<lable>Exporter Name: </lable><%= f.text_field :exporter_name, class: "form-control", placeholder: "Exporter Name"%>
<lable>Vehicle Color: </lable><%= f.text_field :vehicle_color, class: "form-control", placeholder: "Vehicle Color"%>
**its fields**
<% end %>

The error in my new.html.rb First argument in form cannot contain nil or be empty

Displays this in red highlighted

<%=  form_for @border_rotation_export, url: rotation_create_path, method: :post do |f|%>

My guess is that it submits both forms but only has the parameters for one form with the input data. Once I submit, it saves to the database but it gives me the error

**Routes **

  get 'rotation/create', to: 'border_rotation#create'
  
  post 'rotation/create', to: 'border_rotation#create'
Request
Parameters:

{"utf8"=>"✓",
 "authenticity_token"=>"Cu52CIDgrY0b7Yk6edkd7 RTl5yR4qSEqPPrqWtM0nIQVDvw7eYDF36zduJPLjI vVNqCfgtLcMDUEkW6qDOdQ==",
 "border_rotation_import"=>
  {"importer_name"=>"john",
   "vehicle_color"=>"red",
   "rot_num"=>"11sssfeeea",
   "current_date"=>"2021-09-22",
   "current_time"=>"09:37",
   "goods_description"=>"yogurt",
   "license_num"=>"c-11223",
   "entry"=>"c1223"},
 "import_submit"=>"Submit"}

Thank you in advance

CodePudding user response:

You can setup the controller with a lot less redundancy:

# config/routes.rb
resources :rotations, only: [:new, :create]
class BorderRotationsController < ApplicationController

  # GET /rotations/new
  def new
    populate_forms
  end

  # POST /rotations
  def create
    resource = model_class.new(create_params)
    set_ivar(resource) # sets @border_rotation_export or @border_rotation_import
    if resource.save  
      flash[:success] = "#{humanized} successfully created"
      redirect_to action: :new
    else
      populate_forms
      flash[:error] = "#{humanized} could not be created - please try again."
      render :new
    end
  end

  private

  # gets the model class via params[:subtype]
  def model_class
    @model_class ||= begin do
      if params[:border_rotation_export].present?
        BorderRotationExport
      else
        BorderRotationImport 
      end
    end
  end

  def humanized
    model_class == BorderRotationExport ? 'Export' : 'Import'
  end

  def set_ivar(value)
    instance_variable_set(
      "@#{param_key}",
      value
    )  ​
  ​end

  # just sets up the instance variables for the form
  def populate_forms
    @border_rotation_export ||= BorderRotationExport.new
    @border_rotation_import ||= BorderRotationImport.new
  end

  # border_rotation_export or border_rotation_import
  def param_key
    model_class.model_name.param_key
  end
  
  def create_params
    require(param_key).permit(
      :exporter_name, :vehicle_color, :rot_num,
      :current_date,:current_time, :goods_description,
      :license_num, :entry
    )
end

And then use partials so that you can resuse the same form:

# app/views/border_rotations/new.html.erb
<%= render partial: 'form', 
           locals: { border_rotation: @border_rotation_export } %>

<%= render partial: 'form', 
           locals: { border_rotation: @border_rotation_import } %>
# app/views/border_rotations/new.html.erb
<%= form_with model: border_rotation, url: rotations_path do |f| %>
  <div class="field">
     <%= f.label :importer_name %>
     <%= f.text_field :importer_name, class: "form-control" %>
  </div>
  <div class="field">
     <%= f.label :importer_name %>
     <%= f.text_field :importer_name, class: "form-control" %>
  </div>
  # ...
<% end %>

If the requirements diverge use two separate routes/controllers and inheritance instead of blooming out in tons of new code paths.

  • Related