fields_for duplicates during edit - ruby-on-rails

I followed this railscast.
Controller: project_sub_types_controller.rb
def new
#svn_repos = ['svn_software','svn_hardware']
#project_sub_type = ProjectSubType.new
#project_sub_type.repositories.build
end
def edit
#svn_repos = ['svn_software','svn_hardware']
#project_sub_type = ProjectSubType.find(params[:id])
end
Model: project_sub_type.rb
class ProjectSubType < ActiveRecord::Base
belongs_to :project_type
has_many :repositories, :dependent => :destroy
def repositories_attributes=(repos_attributes)
repos_attributes.each do |attributes|
repositories.build(attributes)
end
end
end
View: _form.html.erb
<%= form_for #project_sub_type, :html => {:class => 'project_subtype_form'} do |f| %>
<%= f.label :name, "Project sub type name" %>
<%= f.text_field :name %>
<% for repos in #project_sub_type.repositories %>
<%= fields_for "project_sub_type[repositories_attributes][]", repos do |repos_form| %>
<% #svn_repos.each do |repos| %>
<%= repos_form.check_box :repos_name, {}, "#{repos}", nil %>
<%= h repos -%>
<% end %>
<% end %>
<% end %>
<%= f.submit "Save"%>
This works perfectly during creation of a new record. But Y does the fields_for duplicates during edit. During create I see 2 checkboxes but during edit there are 4 checkboxes which duplicates the other 2 checkboxes. What am I doing wrong?
Update : The more times I click on edit and the duplication increases by 1.

<% for repos in #project_sub_type.repositories %>
<%= fields_for "project_sub_type[repositories_attributes][]", repos do |repos_form| %>
<% #svn_repos.each do |repos| %>
<%= repos_form.check_box :repos_name, {}, "#{repos}", nil %>
<%= h repos -%>
<% end %>
<% end %>
<% end %>
Get rid of that and do:
<%= f.fields_for :repositories do |repo_form| %>
<% #svn_repos.each do |rep| %>
<%= repo_form.check_box :repos_name, {}, rep, nil %>
<%= h rep -%>
<% end %>
<% end %>
Also get rid of repositories_attributes= method in your model and add accepts_nested_attributes_for :repositories
The railscast you linked is 7 years old. :)

Related

My nested attributes are not passing through the strong Params

I have a form for a delivery order that contains a form for a meal inside of it. A meal is made up of items, which are also objects. The form for a delivery looks as so...
<%= form_for #delivery do | f | %>
<%= f.label :address %>
<f.text_field :address $>
<% if #meal != nil %>
<% meal = #meal %>
<% else %>
<% meal = Meal.new %>
<% end %>
<%= f.fields_for meal %>
<%= render partial: "meals/form", locals: {selected_meal: meal} %>
<% end %>
<br>
<%= f.submit "Continue" %>
<% end %>
and the form for the meal looks as so
<label>Meal Name: (Optional) </label>
<%= f.text_field :name %>
<br>
<h4>-----------Pizzas------------</h4>
<%= f.collection_check_boxes :meal_item, Item.pizza_items, :id, :show %>
<br>
<h4>-------Cold Sandwiches-------</h4>
<%= f.collection_check_boxes :meal_item, Item.cold_items, :id, :show %>
<br>
<h4>-------Hot Sandwiches-------</h4>
<%= f.collection_check_boxes :meal_item, Item.hot_items, :id, :show %>
<br>
<h4>-----------Salads-----------</h4>
<%= f.collection_check_boxes :meal_item, Item.salad_items, :id, :show %>
<br>
<h4>------------Pastas------------</h4>
<%= f.collection_check_boxes :meal_item, Item.hot_items, :id, :show %>
<br>
<h4>-----------Chicken-----------</h4>
<%= f.collection_check_boxes :meal_item, Item.hot_items, :id, :show %>
<br>
<%= f.submit "Continue" %>
<% end %>
When the delivery form with the nested meal form is passed, it goes to the delivery # confirm action, and with the strong param, it looks like this...
def confirm
binding.pry
#delivery = Delivery.new()
if (SessionHelpers.is_logged_in?(session))
#credit = SessionHelpers.current_user(session).credit
end
end
private
def delivery_params
params.require(:delivery).permit(:address, :order_user_id, :total_price, :delivered, meal_attributes: [:name, items:[]])
end
Whenever the form is passed, the delivery_params only has the address passed, none of the meal attributes go through, yet they exist in the regular params. How can I fix this?
Probably coming from how you call your nested form.
Maybe try smething like :
<%= f.fields_for :meal do |meal_f| %>
And in your partial :
<%= meal_f.text_field :name %>

Rails fields_for update not working (deleting the parent object)

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

rails how to pass nested parameters

I have a strong parameter like this
params.require(:survey).permit( option_booleans_attributes: [:id, :survey_id, :topic, :answer])
if I use rails f.input I got parameter like
"option_booleans_attributes"=>{"0"=>{"answer"=>"true", "id"=>"5"}, "1"=>{"answer"=>"false", "id"=>"6"}, "2"=>{"answer"=>"true", "id"=>"7"}}}
but I need to show option_booleans topic and let user fill answer
<% #survey.option_booleans.each do |question| %>
<%= question.topic %><br>
<%= radio_button "option_booleans_attributes[]", "answer[#{question.id}]", "true" %>是
<%= radio_button "option_booleans_attributes[]", "answer[#{question.id}]", "false" %>否<br>
<% end %>
But I don't know how to generate the 0 1 2 in the parameter..
about my survey.rb
class Survey < ActiveRecord::Base
has_many :option_booleans
accepts_nested_attributes_for :option_booleans
belongs_to :member
end
class OptionBoolean < ActiveRecord::Base
belongs_to :survey03
and OptionBoolean have topic:string and answer:boolean
I want to let user see the topic and update the answer
It seems you're missing several parts of your form:
#app/controllers/surveys_controller.rb
def new
#survey = Survey.new
#survey.option_booleans.build #-> creates ActiveRecord Object for your form
end
#app/views/surveys/new.html.erb
<%= form_for #survey do |f| %>
<%= f.fields_for :option_booleans do |option| %>
<% #survey.question_booleans.each do |question| %>
<%= question.topic %>
<%= f.radio_button "answer[#{question.id}]", "true" %>
<%= f.radio_button "answer[#{question.id}]", "false" %>
<% end %>
<% end %>
<% end %>
Although I don't quite understand how your system works
You have a survey with many options, but you're passing new attributes to create new options each time. Surely you'd have option_booleans as a join model, with options as an independent model, and:
#app/models/survery.rb
Class Survey < ActiveRecord::Base
has_many :option_booleans
has_many :options, through: :option_booleans
end
What I use now
<li><% #survey03.option_booleans.each do |question| %>
<%= question.topic %><br>
<%= radio_button "option_booleans_attributes[#{question.id}]", "answer", "true", :required => true %>
<%= radio_button "option_booleans_attributes[#{question.id}]", "answer", "false", :required => true %>
<% end %></li>
and in controller
params[:option_booleans_attributes].each do |option_id, attributes|
if option = OptionBoolean.find_by_id(option_id)
option.update_attributes(attributes)
end
end
and I know if I want to generate index just use
<% #survey.option_booleans.each_with_index do |question, index| %>
<%= question.topic %><br>
<%= radio_button "option_booleans_attributes[#{index}]", "answer[#{question.id}]", "true" %>
<%= radio_button "option_booleans_attributes[#{index}]", "answer[#{question.id}]", "false" %>
<% end %>
try select options like this:
#variable_with_booleans = [true, false]
<%= f.select :param, #variable_with_booleans %>
answer to your latest comment:
I don't sure, but try to edit your form
<%= form_for #question do |f| %>
<%= f.label :topic %>
<% #variable_with_booleans = [true, false] %>
<%= f.select :answer, #variable_with_booleans %>
<%= f.submit %>
<% end %>
and edit your strong params in controller,which contains this action

How to build children of a nested form in the controller

I know how to build the 2nd object in a controller but how do you build a third or a fourth?
In my case i need to build 3.
Location - has_many :product_dates, :products
ProductDate - has_many :products & belongs_to :location
Product - belongs_to :location, :product_date
I build the Location and Product Date easily:
def new
#location = Location.new
#location.product_dates.build
end
Now i need to build the products on the form. Can anyone show me how to do this?
EDIT: Complete Answer:
def new
#location = Location.new
product_date = #location.product_dates.build
product_date.products.build
end
<%= form_for #location do |f| %>
<%= f.text_field :business %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates do |date| %>
<%= date.date_select :date %>
<%= date.fields_for :products do |product| %>
<%= product.text_field :name %>
<%= product.text_field :price %>
<%= product.text_field :tag_list %>
<% end %>
<% end %>
<%= f.submit "Create" %>
<% end %>
You'll learn everything in video here.
EDIT:
change the nested part with:
<%= f.fields_for :product_dates do |date| %>
<%= date.date_select :date %>
<%= date.fields_for :products do |product| %>
<%= product.text_field :name %>
<%= product.text_field :price %>
<%= product.text_field :tag_list %>
<% end %>
<% end %>
Because products are nested inside product_dates
add to your controller:
def new
#location = Location.new
#product_dates = #location.product_dates.build
#product = #product_dates.product.build
end
in you ProductDate model:
class ProductDate < ActiveRecord::Base
accepts_nested_attributes_for :products
...
in you Location model:
class Location < ActiveRecord::Base
accepts_nested_attributes_for :product_dates
...
And you form should be like this:
<% f.fields_for :product_dates do |date| %>
<%= date.text_field :content %>
<% date.fields_for :products do |product| %>
<%= product.text_field :content %>
<%end %>
<% end %>

Rails 3 using fields_for in view doesn't work

I'm trying to implement master detail in a rails form with fields_for.
I have one model called Recipe:
class Recipe < ActiveRecord::Base
validates :name, :presence => true
validates :directions, :presence => true
has_many :recipe_ingredients
end
and one model called RecipeIngredient:
class RecipeIngredient < ActiveRecord::Base
belongs_to :recipe
#belongs_to :ingredient
end
In the new controller I populate the ingredients with three empty records like this:
def new
#recipe = Recipe.new
3.times {#recipe.recipe_ingredients.build}
# #ingredients = RecipeIngredient.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #recipe }
end
end
What I would like to do in the view is to output the recipes fields (which works ok) and the three fields for recipe ingredients. In the top part of the view I have this:
<%= form_for :rec do |f| %>
I then list the recipe fields which are displayed correctly, like:
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
I then try to display the ingredient lines but the code never seems to go into the fields_for section:
first try:
<% for ingredient in #recipe.recipe_ingredients %>
This prints out three times
<% fields_for "...", ingredient do |ingredient_form| %>
But this never prints out
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end%>
I have three empty lines in recipe_ingredients and the for loop seems to iterate three times but the code within fields_for never triggers.
Second try:
<% for recipe_ingredient in #recipe.recipe_ingredients %>
b
<% fields_for "...", recipe_ingredient do |recipe_ingredient| %>
Rec: <%= recipe_ingredient.text_field :description %>
<% end %>
<% end %>
Third try (based on the answer here):
<% form_for :recipe do |f| %>
<% f.fields_for ingredients do |ingredient_form| %>
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end %>
Is there something obvious I'm doing wrong?
You should use <%= instead of <% when using form_for and fields_for
The correct code should look like this:
<%= form_for :recipe do |f| %>
<%= f.fields_for :ingredients do |ingredient_form| %>
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end %>
Switch it up to
<% form_for :recipe do |f| %>
<% f.fields_for :ingredients do |ingredient_form| %>
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end %>

Resources