I'm having issues with the implementation of a nested form for a model with has_many through relationship
I have 3 models: Reservation, Table and Collection (Join Model for these two)
In my Reservation Controller I have these two methods:
def new
#reservation = Reservation.new
#tables = Tables.all
#tables.size.times {#reservation.collections.build}
end
and
def reservation_params
params.require(:reservation).permit(:name, collections_attributes: [ :table_id, :units_sold],
tables_attributes: [:units, :title])
end
my form view is as following:
<%= form_for [current_user, #reservation] do |f| %>
<header>
<h1>Make Reservation</h1>
</header>
<%= f.text_field :name, placeholder: "Name" %>
<%= f.fields_for :collections do |builder| %>
<%= render 'nested_form', :f => builder %>
<% end %>
<%= f.submit "Save" %>
<% end %>
and my _nested_form.html.erb file:
<%= f.number_field :units_sold, placeholder: "Units" %>
<%= check_box_tag :table_id %>
My problem is, whenever I save a new entry on the database he assigns the same table_id to all collections association, e.g:
I want to receive the Parameters hash such as:
"collections_attributes"=>{"0"=>{"units_sold"=>"5", "table_id"=>"1"}, "1"=>{"units_sold"=>"6", "table_id"=>"2"}}}
Instead what I'm getting is:
"collections_attributes"=>{"0"=>{"units_sold"=>"5", "table_id"=>"1"}, "1"=>{"units_sold"=>"6", "table_id"=>"1"}}}
How do I fix this for it to give the correct table_id for each collection?
It would be better if you provide your models' snippet that shows their associations.
Anyway, according to your form; One Reservation has many tables through collections.
change:
<%= check_box_tag :table_id %>
to
<% #tables.each do |table| %>
<li>
<%= f.radio_button :table_id %>
<%= f.label :table_id, table.name %>
</li>
<% end %>
By this, you will be able to choose one table from all for each collection using radio button.
Hope this will help!
Related
I have a form that saves attributes to two models Company and nested model Address in a single form using simple_nested_form_for and simple_fields_for.
The attributes:
Company:
-legal form
-uploads
Address:
-name
-website
In my form I wish to change the order of the fields
-name (Address model)
-legal form (Company model)
-website (Address model)
-uploads (Company model)
thus interchanging the form attributes and nested_field attributes
I tried the following, but that did not seem to work.
<%= simple_nested_form_for #company do |f| %>
<%= f.simple_fields_for :address do |c| %>
<%= c.input :name %>
<% end %>
<%= f.input :legal_form %>
<%= f.simple_fields_for :address do |c| %>
<%= c.input :website %>
<% end %>
<%= f.input :uploads %>
<% end %>
How do I make this work?
While it doesn't look like all your attributes line up ( you said uploads was address and website was in company in your attributes list but the form doesn't match that ) there is still a simple solution to your question.
Nested fields rely on their builder to denote which part of the params hash to put them in. So simply call the builder that you need.
<%= simple_nested_form_for #company do |f| %>
<%= f.simple_fields_for :address do |c| %>
<%= c.input :name %>
<%= f.input :legal_form %>
<%= c.input :website %>
<%= f.input :uploads %>
<% end %>
<%= f.submit %>
<% end %>
In each place that you need the company fields, you'll call builder f and in each place you need the address fields, you'll call builder c - but nested them all inside the lowest common denominator so they're all available.
I am having some difficulty to figure out why the post data from the form is not posted correctly.
I have to models: Child and Parent
in the form of Child i am nesting a form of Parent in this way:
<%
parent = (child.parent) ? parent : Parent.new
%>
<%=f.fields_for :parent, parent do |builder| %>
<%= render 'parent_fields', :fp => builder %>
<% end %>
The parent_fields form is as follows:
<% #all_parents = Parent.all %>
<% parent = fp.object %>
<%= fp.fields_for :parent do |builder| %>
<%= builder.input :parent_id, :as => :select, :label => 'Parent: ', :required => false,
:collection => options_from_collection_for_select(#all_parents, "id", "name", parent.id), :include_blank => '- Select -' %>
<% end %>
The posted data hash shows as follows:
"parent_attributes"=>{"parent"=>{"parent_id"=>"6"}, "id"=>"36"}
where 36 is the old parent id and 6 is the new one.
When i do update_attributes it does not work which is normal because it would work if the hash would be like this way:
...
"parent_id" => 6
"parent_attributes"=>{"id"=>"36", ....}
...
I am working on a legacy code. It is also possible that data was modified by javascript. The purpose of this post is to make sure that the way I am writing the form is the right way because I am new to nested forms.
Thank you
There are two possibly scenarios you want to consider:
1. A child needs to select an existing parent it belongs to.
2. A child needs to create a brand new parent that it belongs to.
It appears that you want to do #1, select an existing parent. If so, you do not need fields_for. Fields for is for creating new relations.
I'll show you some example code from an application I'm working on about schools, where a student belongs_to a grade level.
app/views/students/_form.html.erb
<%= form_for #student do |student_form| %>
<%= student_form.text_field :first %>
<%= student_form.text_field :last %>
<%= student_form.collection_select :grade_level_id, GradeLevel.all, :id, :name %>
<%= student_form.submit "Save" %>
<% end %>
Now, using your models (Child and Parent):
app/views/children/_form.html.erb
<%= form_for #child do |form| %>
<%= form.text_field :child_name %>
<%= form.number_field :age %>
<%= form.collection_select :parent_id, Parent.all, :id, :name %>
<%= form.submit "Save" %>
<% end %>
Note that I just put Parent.all straight into the collection_select. Creating #all_parents above isn't necessary.
EDIT
If you want to create new parents every time...
app/views/children/_form.html.erb
<%= form_for #child do |form| %>
<%= form.text_field :child_name %>
<%= form.number_field :age %>
<% form.fields_for :parent, #child.parent do |parent_fields| %>
<%= parent_fields.text_field :parent_name %>
<%= form.submit "Save" %>
<% end %>
I have fields_for form for update like below:
<%= form_for #cuisine, url: {action: "update" } do |f| %>
<%= f.text_area :name %>
<% #cuisine.ingredients.each do |ing| %>
<%= f.fields_for ing do |ingredient_fields|%>
<%= ingredient_fields.text_area :name, :value=> ing.name %>
<%= ingredient_fields.hidden_field :_destroy%>
<%= link_to_remove_fields 'Remove this ingredient', f %>
<% end %>
<% end %>
<% end %>
my cuisines_controller:
def update
#cuisine = Cuisine.find(params[:id])
if #cuisine.update_attributes(cuisine_params)
redirect_to root_path
else
redirect_to edit_cuisine_path
end
end
Though this shows the form correctly (showing forms filled with #cuisine and its ingredients' info), after reloading the page the #cuisine object gets deleted even when I don't push the submit button.
Any idea what's going on or how to update nested attributes using fields_for?
Thanks in advance.
First you should just use fields_for like this:
<%= f.fields_for :ingredients do |ingredient_fields|%>
<%= ingredient_fields.text_area :name %>
<%= ingredient_fields.hidden_field :_destroy %>
<%= link_to_remove_fields 'Remove this ingredient', f %>
<% end %>
Second you should first check to see if the cuisine_params in your controller permit those attributes:
params.require(:cuisine).permit(:name, ingredients_attributes:[:id, :name, :_destroy])
Lastly, make sure your model has this accepts_nested_attributes_for :ingredients, allow_destroy: true
I try to create a furniture object, which is in relation by a has_many_and_belongs_to with stores, this is my model:
class Furniture < ActiveRecord::Base
attr_accessible :area, :description, :name, :size
has_and_belongs_to_many :stores
end
My problem is that I don't know how create a new furniture, because i try to associate furniture with one or more store with check box, but I obtain this error: undefined method merge for #<Store:0x007ff16ae27e40>.
These are my view with form and my controller with new and create action:
View:
<%= form_for #furniture do |f| %>
<%= f.label :name %>
<%= f.text_field :name %> <br><br>
<%= f.label :description %>
<%= f.text_field :description %> <br><br>
<%= f.label :size %>
<%= f.text_field :size %> <br><br>
<% #store.each do |store| %>
<div>
<%= f.check_box :stores, store %>
<%= store.name %>
</div>
<% end %>
<%= f.submit %>
<% end %>
Controller:
def new
#furniture = Furniture.new
#store = Store.order('name ASC')
end
def create
#furniture = Furniture.create(params[:furniture])
redirect_to admins_path
end
How can I solve it?? Have you some suggestion to create a new object with this relation ship??
Thank you very much
EDIT:
I have a join table between furniture and store
The has_and_belongs_to association adds a method collection_singular_ids= that for the current case will be #furniture.store_ids=. According to the docs
The collection_singular_ids= method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate.
So, you can use this idea to add the stores to your furniture. Replace
<% #store.each do |store| %>
<div>
<%= f.check_box :stores, store %>
<%= store.name %>
</div>
<% end %>
with
<% #store.each do |store| %>
<div>
<%= f.check_box :store_ids, {:multiple => true}, store.id, nil %>
<%= store.name %>
</div>
<% end %>
In my Ruby on Rails application I want to allow the adding/editing of a nested model which itself has an associated model.
model Survey
string title
has_many questions
model Question
string question
belongs_to category
model Category
string name
For the sake of argument let's assume that the user should always have to enter a new category when entering a question (I couldn't come up with a better example, sigh).
In my model/survey/edit.html.erb I have a working setup for adding questions and saving them. However when I added the Category model to the picture, I now face the problem that when adding a new Question, there is no corresponding Category name-field displayed. I suspect this is because even though I do call Question.new, I do not call question.category.build - and I have no idea where/how to do that.
My edit.html.erb:
<h1>Editing Survey</h1>
<%= render :partial => 'form' %>
My _form.html.erb:
<% form_for(#survey) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<div id="questions">
<% f.fields_for :questions do |q| %>
<%= render :partial => 'question', :locals => { :pf => q } %>
<% end %>
</div>
<%= add_a_new_child_link("New question", f, :questions) %>
<% end %>
My _question.html.erb:
<div class="question">
<%= pf.label :question %>
<%= pf.text_field :question %>
<% pf.fields_for :category do |c| %>
<p>
<%= c.label :name, "Category:" %>
<%= c.text_field :name %>
</p>
<% end %>
</div>
A quick fix for your situation is to use virtual attributes.
EG, in your Question model:
def category_name=(new_name)
if category then
category.name = new_name
else
category = Category.new(:name => new_name)
end
end
def category_name
return category.name if category
""
end
In your _question, there no need to use nested form. Just add something like:
<%= pf.text_field :category_name %>
I didn't test it, but you probably caught the ideea.