Search code examples
ruby-on-railsformsparametersstrong-parametersform-helpers

Number_field_tag to create unique records for each item/ quantity


I'm using a number_field_tag to allow users to indicate how many of a given item they have. For each of these items then, a new record should be created in the model. Default quantity for all item fields is 0.

I'm a bit confused on how to get the params to pass appropriately (i.e., how to write the strong parameters and the form code). The controller code that I've written presumes I'll get a hash that looks like this:

itemrecord = {
  "tent" => 1
  "sleeping bag" => 0
  ...
}

And then that way, I can make the records with the following create code (where :item_name is the attribute for the model Inventory):

items_to_be_saved = []
   inventory_params.each do |item, quantity|
      quantity.times do
         items_to_be_saved << ( :item_name => item )
      end
   end

Currently the view/ strong parameters code I have below is producing the following output, which is different from what I need in that :item_record is an array of quantities without the relevant item being selected.

Parameters: {"utf8"=>"✓", "authenticity_token"=>"m2NMruoFRr6lpsuVMK9UthlY0bsJsPmf1LWce2uKaH4=", ":itemrecord"=>["", "", "", "", "", "", "", "", "2", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], "commit"=>"Go!", "method"=>"post"}

Form code

          <%= form_tag inventories_path method: :post do %>

            <div class="col-xs-12">
              <p><b>Items people are asking for</b></p>
            </div>

            <% @wishlist.each do |category, list| %>
              <div class="col-xs-2">
                <div class="form-group box">
                  <h5> <%="#{category}"%> </h5>
                    <% list.each do |thing| %>
                        <%= number_field_tag ":itemrecord[]", "#{thing}", {:size => 1, :placeholder => '0', :min => 0} %>
                        <%= label_tag "#{thing}" %>
                      </br>
                    <% end %>
                </div>
              </div>  
            <% end %>

              <%= submit_tag "Go!", class: "btn btn-primary btn-large btn-block" %>
            </div>
          <% end %>

Controller code

def inventory_params
  params.require(":itemrecord")
end

EDIT! I have a solution! But the params part of it is very hacky and needs to be updated. Here's the code that works:

View

<%= number_field_tag "#{thing}", :quantity, min: 0, placeholder: 0 %>

Controller

def create

items_to_be_saved = []
inventory_params.each do |item, quantity|
  quantity = quantity.to_i
  quantity.times do
    items_to_be_saved << ({:signup_id => @signup_parent.id, :item_name => item })
  end
end

if Inventory.create items_to_be_saved
    flash[:success] = "Thanks!"
    redirect_to root_path
else
    render new_inventory_path
end

end

def inventory_params
    params.except(:action, :controller, :method, :commit, :utf8, :authenticity_token)
end

The problem is that having params.except defeats the purpose of a "strong" parameter. I basically need the params to be passed to be any one of a laundry list of items that is defined by the controller. Similar to the form, the controller code is

def wishlist
    @wishlist = {
        "Category1" => ["ItemA", "ItemB"],
        "Category2" => ["ItemC", "ItemD"],
    }
end

As you can see in the view, the ItemA, ItemB, ItemC, ItemD are the names of each form field generated, and the key of the params hash (with :quantity being the value). The problem is how to permit it. The below is not working with an error: undefined method[]' for nil:NilClasson thepermit` line

def inventory_params
  @wishlist.each do |category, list|
    list.each do |thing|
      params.permit[thing][:quantity]
      params.reject { |k, v| v == "" }
    end
  end
end

Solution

  • OK I solved it. And I realized it was really simple... this is what happens when you work too long... the brain just stops

    Controller code:

    def create
    
        items_to_be_saved = []
        inventory_params.each do |item, quantity|
          quantity = quantity.to_i
          quantity.times do
          items_to_be_saved << (:item_name => item )
        end
    end
    
    if Inventory.create items_to_be_saved
        flash[:success] = "Thanks!"
        redirect_to root_path
    else
        render new_inventory_path
    end
    
    end
    
    def inventory_params
        params.permit[:quantity]
        params.reject { |k, v| v == "" }
    end
    

    View code:

              <%= form_tag inventories_path method: :post do %>
    
                <div class="col-xs-12">
                  <p><b>Items people are asking for</b></p>
                </div>
    
                <% @wishlist.each do |category, list| %>
                  <div class="col-xs-2">
                    <div class="form-group box">
                      <h5> <%="#{category}"%> </h5>
                        <% list.each do |thing| %>
                            <%= number_field_tag "#{thing}", :quantity, min: 0, placeholder: 0 %>
                            <%= label_tag "#{thing}" %>
                          </br>
                        <% end %>
                    </div>
                  </div>  
                <% end %>
    
                  <%= submit_tag "Go!", class: "btn btn-primary btn-large btn-block" %>
                </div>
    
              <% end %>