Rails fields_for update not working (deleting the parent object) - ruby-on-rails

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

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 5.1.4 fields_for for multiple objects

I have an Author and Book model. An Author can have many Book, but a Book can only have one Author.
During the creation of a new Author, how do I add a "New Book" button which will add a fields_for for the Author form? I want to be able to add more than one Book. So far, the solution that I have found is just to add a fixed number of fields_for, like this:
<%= form_with(model: author, local: true) do |form| %>
...
<% 5.times do %>
<%= form.fields_for :books do |books| %>
...
<% end %>
<% end %>
...
<% end %>
I do not want it to be like this, what if the author has more than 5 books? I want to be able to add books dynamically. Any solutions?
If you fine with adding a new dependency, there's cacoon gem, which allows you easier handle nested forms.
It's an additional dependency, but the code for adding a new associated record is simple as:
<%= form_for author do |f| %>
...
<%= f.fields_for :books do |book| %>
<%= render 'book_fields', f: book %>
<%= link_to_add_association 'add book', f, :books %>
<%end%>
author.rb
accepts_nested_attributes_for :books,
:allow_destroy => true,
:reject_if => :all_blank
In your view file
<div class="bank_account_details">
<%= f.fields_for :bank_account_details do |builder| %>
<p>
Book: <%= builder.text_field :name %>
<%= builder.check_box :_destroy %>
<%= builder.label :_destroy, "Remove Book" %>
</p>
<% end %>
<div>
<%= link_to_add_fields "Add Book", f ,:books %>
In your controller add parameters
params.require(:author).permit(:name, books_attributes: [:id, :name, :_destroy])

fields_for duplicates during edit

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. :)

Sending the wrong Params on a nested form

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!

Nested form shows too many fields! Rails Beginner

I as Rails Beginner created an simple demo app to experiment with nested forms.
But somehow my code shows strange byproducts:
My only aim was to create new treatments for patients on the patients show page, and now
it show input fields with yet created treatments and some other crazy stuff!! What did i wrong? My steps so far:
rails new hama
cd hama
rails g scaffold Patient name:string
rails g model Treatment content:string
rake db:migrate
Patient model:
attr_accessible :name, :treatments_attributes
has_many :treatments, :dependent => :destroy
accepts_nested_attributes_for :treatments
Treatment model:
attr_accessible :content
belongs_to :patient
In patient/show:
<b>Name:</b>
<%= #patient.name %>
</p>
<p>
<b>Treatments:</b>
<%= #patient.treatments.each do |treatment| %>
<%= treatment.content %>
<% end %>
</p>
<%= form_for #patient do |f| %>
<%= f.fields_for :treatments do |ff| %>
<%= ff.text_field :content %>
<% end %>
<%= f.fields_for :treatments do |ff| %>
<%= ff.text_field :content %>
<% end %>
<%= f.submit %>
<% end %>
And in Patient controller:
def show
#patient = Patient.find(params[:id])
treatment = #patient.treatments.build
respond_to do |format|
format.html # show.html.erb
format.json { render json: #patient }
end
end
Are you talking about where it shows all the internals of your Treatment objects?
Change this:
<%= #patient.treatments.each do |treatment| %>
to this:
<% #patient.treatments.each do |treatment| %>
Using <%= %>, with the =, means to output the result of that Ruby line on to the page. Without it, it's just code that Ruby runs.
Firstly you should remove the = from this line:
<%= #patient.treatments.each do |treatment| %>
You don't want to display the output of the each. The loop contents provide the output. Just use:
<% #patient.treatments.each do |treatment| %>
All the other fields are output since that's what your code asks for. This part of your code is showing all of the same fields twice:
<%= f.fields_for :treatments do |ff| %>
<%= ff.text_field :content %>
<% end %>
<%= f.fields_for :treatments do |ff| %>
<%= ff.text_field :content %>
<% end %>
If there are two specific input fields for a treatment, then there needs to be two different attributes.

Resources