Rails form_for only submitting last input - ruby-on-rails

Im trying to create inputs by looping each product and have one form submission for all the inputs. Currently, the form only submits the last input. How would I make it so all the inputs get submitted?
<%= form_for :inventory do |f| %>
<% #products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.measurement %></td>
<td><%= f.number_field :amount, class: 'form-control' %></td>
<%= f.hidden_field :product_id, :value => product.id %>
</tr>
<% end %>
<%= f.submit %>
<% end %>

I dont know your use case but you can use the gem cocoon for doing that. There will also be a link to add/remove another product.
https://github.com/nathanvda/cocoon

You can iterate with each_with_index:
<%= form_for :inventory do |f| %>
<% #products.each_with_index do |product, i| %>
<tr>
<%= f.hidden_field "product_id[#{i}]", :value => product.id %>
</tr>
<% end %>
<%= f.submit %>
<% end %>
Like that the output is not very elegant (something like "product_id"=>{"0"=>"1", "1"=>"2", "2"=>"3"... }) but it's for the example to show how every hidden field needs a unique key.
You can define your params in a better way to use them in the controller, just keep them unique.

Related

ActionController::ParameterMissing and multi select rows in a table

I am trying to create a button in View that will create a new record and display in another controller and then display that View.
However I get this error when I click that button.
ActionController::ParameterMissing in JobHeadersController#create
param is missing or the value is empty: job_header
# Never trust parameters from the scary internet, only allow the white list through.
def job_header_params
params.require(:job_header).permit(:company_id, :customer_id, :name, :del_address1, :del_address2, :del_address3, :del_address4, :del_postcode, :tel, :created_by)
end
end
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"BLAHBLAHBLAHg==",
"company_id"=>"2",
"customer_id"=>"1",
"name"=>"Nash Labs",
"del_address1"=>"23 Taylor Road",
"del_address2"=>"Odsal",
"del_address3"=>"Bradford",
"del_address4"=>"West Yorkshire",
"del_postcode"=>"BD6 1BH",
"tel"=>"07522189605",
"created_by"=>"2",
"button"=>""}
My View code is
<%= form_tag({controller: "job_headers", action: "create"}, method: "post") %>
<% #other_assets.each do |assets| %>
<tr>
<td><%= check_box_tag 'selected_assets[]', assets.id%></td>
<td><%= assets.service_type %></td>
<td><%= assets.asset_type %></td>
<td><%= assets.make %></td>
<td><%= assets.model %></td>
<td><%= assets.serial_no %></td>
<td><%= format_date(assets.date_next) %></td>
<td><%= link_to "Notes", customer_asset_service_register_path, :id => 'notesModal', "data-toggle" => "modal", 'data-target' => '.bs-example-modal-lg' %></td>
</tr>
<% end %>
</table>
</div>
<%= hidden_field_tag :company_id, #customer.company_id %>
<%= hidden_field_tag :customer_id, #customer.id %>
<%= hidden_field_tag :name, #customer.name %>
<% if #customer.del_address1.blank? %>
<%= hidden_field_tag :del_address1, #customer.address1 %>
<% else %>
<%= hidden_field_tag :del_address1, #customer.del_address1 %>
<% end %>
<% if #customer.del_address1.blank? %>
<%= hidden_field_tag :del_address2, #customer.address2 %>
<% else %>
<%= hidden_field_tag :del_address2, #customer.del_address2 %>
<% end %>
<% if #customer.del_address1.blank? %>
<%= hidden_field_tag :del_address3, #customer.address3 %>
<% else %>
<%= hidden_field_tag :del_address3, #customer.del_address3 %>
<% end %>
<% if #customer.del_address1.blank? %>
<%= hidden_field_tag :del_address4, #customer.address4 %>
<% else %>
<%= hidden_field_tag :del_address4, #customer.del_address4 %>
<% end %>
<% if #customer.del_address1.blank? %>
<%= hidden_field_tag :del_postcode, #customer.postcode %>
<% else %>
<%= hidden_field_tag :del_postcode, #customer.del_postcode %>
<% end %>
<%= hidden_field_tag :tel, #customer.tel %>
<%= hidden_field_tag :created_by, current_user.id %>
<div class="box-tools pull-right">
<%= button_tag(type: "submit", class: "btn btn-primary pull_right") do %>
<i class='fa fa-calendar'></i> Create Job
<% end %>
<% end %>
If I am reading the error right it is expecting the param "job_header" and it is null however, this is to create a new job_header record and so I can't pass that param?
If anyone also knows how I Can put a tick box against my table rows so that the selected #other_asset id's get passed to a param as an array please also let me know. It will save me lots of googling.
Thanks in advance
ActionController::ParameterMissing in JobHeadersController#create
param is missing or the value is empty: job_header
You are using a form_tag to submit the data, so there won't be any key(model instance) to which the params append. You just need to change
params.require(:job_header).permit(:company_id, :customer_id, :name, :del_address1, :del_address2, :del_address3, :del_address4, :del_postcode, :tel, :created_by)
to
params.permit(:company_id, :customer_id, :name, :del_address1, :del_address2, :del_address3, :del_address4, :del_postcode, :tel, :created_by)
Rails way: Use form_for #job_header do |f|
to create a form scoped by #job_header and in job_header_params will be:
{"utf8"=>"✓", "authenticity_token"=>"BLABLABLA",
"job_header": {
"company_id"=>"2",
"customer_id"=>"1",
"name"=>"Nash Labs",
"del_address1"=>"23 Taylor Road",
"del_address2"=>"Odsal",
"del_address3"=>"Bradford",
"del_address4"=>"West Yorkshire",
"del_postcode"=>"BD6 1BH",
"tel"=>"07522189605",
"created_by"=>"2"},
"button"=>""}
The exception is saying that the required node (:job_header) is missing and can find the permitted params (params['job_header'] => nil).
More at https://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormHelper.html
Pay attention to these items that you didn't get it:
https://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
https://guides.rubyonrails.org/form_helpers.html
And if you already have the information for those hidden fields (in #customer), why you send to the view to receive the """same""" information back from it? (The same with " because a user can alter this data with a page inspection and send maliciously code...)
Only fill these attrs on the controller.

Rails - Simple_fields_for not submitting multiple records

I'm trying to create a form that allows a user to select different choices for each category on the same form, and each of these will create its own model. My problem is getting the form to submit multiple parameters. My code is as follows:
<%= simple_form_for choices_path do |f| %>
<td><%= person.fullname %></td>
<td><%= person.email %></td>
<td><%= person.phone %></td>
<% if Category.any? %>
<%= f.simple_fields_for :choices do |g| %>
<% Category.all.each do |category| %>
<td>
<%= g.input :item_id, as: :select, collection: booking.venue.menu_items(category) %>
<%= g.hidden_field :admin_id, value: person.id %>
</td>
<% end %>
<% end %>
<% end %>
<td><%= person.completed? %></td>
<td><%= f.submit %></td>
<% end %>
The idea obviously being to create a new form for each category. This works until submitting the data, where only the last form's data is submitted. My paramaters are as follows:
{"utf8"=>"✓", "authenticity_token"=>"tf3DSLGHyOVEVJkcLjSVE9HDJbjn1CIaYBJIfHFw6RYH8tcn0tNilWVIjzyvcjXYm2ovKNO5A31+TktGA8X2+Q==",
"/choices"=>{"choices"=>{"item_id"=>"Dessert 1", "admin_id"=>"3"}},
"commit"=>"Save /choices",
"venue_id"=>"1",
"booking_id"=>"26"}
I can see that its creating a hash and is ready to submit multiple choices, however it is only the last record's data that is submitted.
Any help on how to get multiple records to update is greatly appreciated.
Thanks in advance.
The simple form association helper might be what you are looking for:
link

Rails - update multiple resource entries with one link

I have a table of forms
<% #group.lessons.each do |lesson| %>
<%= form_for [#group, lesson] do |f| %>
<tr id='<%= lesson.id%>' >
<td><%= f.text_field :time %></td>
<td><%= f.text_field :day %></td>
<td><%= f.text_field :subject %></td>
<td><%= f.text_field :teacher %></td>
<td><%= f.text_field :room %></td>
<td><%= f.submit 'Update'%></td>
<td><%= link_to 'Delete', [lesson.group, lesson], method: :delete%></td>
</tr>
<%end%>
<%end%>
Each form updates an entry when the "update" button is clicked. But when you edit two entries and update only one, the info you edited in the other one is gone.
I want to have a button to update each entry in the table. How do I do this?
UPDATED:
First in model:
class Group < AR::Base # possibly you'r using ActiveRecord
attr_accessible :lessons_attributes
accepts_nested_attributes_for :lessons, :allow_destroy => true
has_many :lessons
end
and then in your view: # e.g. views/groups/_form.html.erb
<table>
<%= form_for #group do |f| %>
<%= f.error_messages %>
<%= f.fields_for :lessons do |lesson_form| %>
<%= render "lessons/lesson", :f => lesson_form%>
<% end %>
<tr><td><%= f.submit 'Update'%></td></tr>
<% end %>
</table>
and in views/lessons/_lesson.html.erb
<tr>
<td>
<%= f.text_field :subject %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Lesson" %>
</td>
</tr>
I think this is more of an html issue than a rails issue. You simply can't submit more than one form using plain html. That's why you're losing one form when you submit the other.
What you could do however is update multiple lessons that belong to the same group using nested attributes. Here are some resources for that:
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
http://railscasts.com/episodes/196-nested-model-form-part-1
https://github.com/ryanb/nested_form

fields_for with association question

How do I use association data from within a fields_for?
I've got a has many through relationship between users, schools and schools_users. A user can have multiple schools and a school has multiple users. In schools_users there is a user_role field in addition to the common user_id and school_id.
In the show view I have:
<% #school.schools_users.each do |user| %>
<tr><td><%= user.user.first_name %> <%= user.user.last_name %></td><td><%= user.user_role %></td></tr>
<% end %>
but I can't figure out how to do the same thing from within the fields_for on the edit page.
<%= f.fields_for :schools_users do |f| %>
<tr>
<td><%= NEED USER NAME HERE %></td>
<td><%= f.select(:user_role, active_role_options)%></td>
<td><%= link_to_remove_fields 'Delete', f %></td>
</tr>
<% end %>
Thanks for any help!
Firstly: You're assigning the block variable of your fields_for to f, which is the same f your form_for uses. You should use a different name, like user_fields.
With that:
<%= f.fields_for :schools_users do |user_fields| %>
<tr>
<td><%= user_fields.text_field :first_name %></td>
...
<% end %>

Rails 3 submit a form with multiple records

I'm new to rails so this is probably a basic question. I am trying to create a form where the user can create 3 records at once. I want the user to only have to click the submit button once. I'm submitting to my Review model a name, comment, and rating. Currently, only the last record is entered into the database.
<%= form_for([#user,#review]) do |f| %>
<table>
<tr>
<td>Rank</td>
<td>Name</td>
<td>Comment</td>
</tr>
<tr>
<td>1</td>
<td><%= f.text_field :name %></td>
<td><%= f.text_field :comment %></td>
<%= f.hidden_field :rating, :value=> "5" %>
</tr>
<tr>
<td>2</td>
<td><%= f.text_field :name %></td>
<td><%= f.text_field :comment %></td>
<%= f.hidden_field :rating, :value=> "3" %>
</tr>
<tr>
<td>3</td>
<td><%= f.text_field :name %></td>
<td><%= f.text_field :comment %></td>
<%= f.hidden_field :rating, :value=> "1" %>
</tr>
</table>
<div class="actions">
<%= f.submit "Create my top 3" %>
</div>
<% end %>
Any advice is appreciated. Thanks.
I would recommend using fields_for for this:
<%= form_for([#user, :reviews]) do |f| %>
<% #reviews.each do |review| %>
<%= fields_for review do |r| %>
<%= render "reviews/form", :r => r %>
<% end %>
<% end %>
<% end %>
To make this work, you will need to build as many review objects as you require in your controller:
def new
# you could also have this in a before_filter...
#user = User.find(params[:id])
#reviews = Array.new(3) { #user.reviews.build }
end
This would create new instances of review records for this user, which is different from new records. Instances are simply Ruby objects. Now because you've called #user.reviews.build three times, you'll see three reviews in your view.
def create
#user = User.find(params[:id])
#reviews = Review.create(params[:reviews])
# Some more logic for validating the parameters passed in
end
This will create three new Review objects and link them to #user, assuming all three are valid.
You'll need to tell rails its an array. First, read this section of this article:
For your purpose, you'll need to build the form by hand:
<%= form_tag 'foo' do %>
<% [1,3,5].each do |i| %>
<%= text_field_tag 'review[][name]' %>
<%= text_field_tag 'review[][comment]' %>
<%= hidden_field_tag 'review[][rating]', :value => i %>
<% end %>
<% end %>

Resources