Rails 3 submit a form with multiple records - ruby-on-rails

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 %>

Related

Rails form_for only submitting last input

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.

Rails - creating place with weekdays in one form

I created a model for a Place
class Place < ApplicationRecord
has_many :open_days, dependent: :destroy
end
and a model for OpenDay:
class OpenDay < ApplicationRecord
belongs_to :place
end
I want to be able to create a record of this place (what I have now is simple textfields) with day of the weeks (and hours) that the place is opened at.
My current form:
<%= form_for(#place) do |f| %>
<%= f.label(:name) %>
<%= f.text_field(:name, placeholder: "Place's name", class: "form-control") %>
<%= f.label(:street) %>
<%= f.text_field(:street, placeholder: "Street", class: "form-control") %>
<%= f.fields_for :open_days do |open_day| %>
<%= open_day.text_field :day %>
<% end %>
....
<% end %>
My new controller
def new
#place = Place.new
7.times do
#place.open_days.build
end
end
I decided to go with a table (code below) but I have absolutely no idea how to create a form for another model inside my existing form for #place. And what's more to be able to save multiple records using this form. Searched through SO but came with noting.
EDIT
I somehow was able to do is, but now there is this problem:
....
<tbody>
<tr>
<th>Open?</th>
<%= f.fields_for :open_days do |o_day| %>
<td><%= o_day.text_field :day, class: "form-control" %></td>
<% end %>
</tr>
<tr>
<th>From:</th>
<%= f.fields_for :open_days do |o_day| %>
<td><%= o_day.text_field :from_time, class: "form-control" %></td>
<% end %>
</tr>
<tr>
<th>To:</th>
<%= f.fields_for :open_days do |o_day| %>
<td><%= o_day.text_field :to_time, class: "form-control" %></td>
<% end %>
</tr>
</tbody>
First table row is populated with input with names like
name="place[open_days_attributes][0][day]"
name="place[open_days_attributes][1][day]"
name="place[open_days_attributes][2][day]"
name="place[open_days_attributes][3][day]"
name="place[open_days_attributes][4][day]"
name="place[open_days_attributes][5][day]"
name="place[open_days_attributes][6][day]"
I would expect the next row to start also from 0 to be like this:
name="place[open_days_attributes][0][from_time]
but instead it is like this:
name="place[open_days_attributes][7][from_time]
How to change it to be iterating from 0 again?
you should use nested attributes and form_for#fields_for
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for

checkboxs in a table created via form_for

I'm new to RoR so apologies if the answer is super simple. I'm trying to create a table that allows users to select other users that can collaborate on a wiki. The issue I'm having is that no matter which checkbox you select on the table. It only toggles the topmost option.
here is the code in question:
<%= form_for [#wiki, #wiki.collaborators.build] do |f| %>
<table class="bordered hoverable">
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td class="right-align"><%= f.check_box :user_id %><%= f.label :user_id, "Give Access" %></td>
</tr>
<% end %>
</tbody>
</table><br /><br />
the controller values in new
def new
#wiki = Wiki.find(params[:wiki_id])
#collaborator = Collaborator.new
#users = (User.all - [current_user])
end
The problem here is that through check_box's you can't get more than one user selected. In order to select multiple data, you need to use f.collection_select.
Here's how:
<%= f.collection_select :user_id, #users, :id, :name, {prompt: "Please select collaborators"}, {multiple: true} %>
To select multiple the the name of the checkbox should not be :user but contain the user id. Try something like that:
<%= form_for [#wiki, #wiki.collaborators.build] do |f| %>
<%= f.fields_for :collaborators do |c| %>
<table class="bordered hoverable">
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td class="right-align"><%= c.check_box user.id %><%= f.label user.id, "Give Access" %></td>
</tr>
<% end %>
</tbody>
</table><br /><br />
<% end %>
<% end %>
The controller would then recieve params like that:
{:collaborators => {1 => '0', 2 => '1'}
showing that user with id 1 was not checked, user with id 2 was checked

Form with route direction does not work

I have a form set up with the following code:
<h2>Add collaborators to the wiki </h2>
<table>
<tr>
<th>Name</th>
<th>Email</th>
<th>Give Access</th>
</tr>
<tr>
<%= form_for (#collaboration) do |f| %>
<% #users.each do |user| %>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td> <%= f.collection_select :user_id, User.all, :id, :name, prompt: true %> </td>
</tr>
<%= f.submit %>
<% end %>
</table>
<%= f.submit %>
<% end %>
And my routes are set up like this:
resources :wikis do
resources :collaborations
end
And in my controller I defined my variables like this:
def new
#wiki = Wiki.find(params[:wiki_id])
#collaboration = #wiki.collaborations.new
end
But when I visit the page clicking on a link I created
<%= link_to 'Add Collaborator', new_wiki_collaboration_path(#wiki) %>
I still get this error:
undefined method `collaborations_path' for #<#<Class:0x007f8b6a5a8a00>:0x007f8b67820c90>
Any thoughts on what goes wrong here?
Your form here just goes to collaboration_path which you've not defined.
<%= form_for (#collaboration) do |f| %>
<% end %>
You need to include the wiki
<%= form_for ([#wiki, #collaboration]) do |f| %>
<% end %>

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

Resources