Nested form shows too many fields! Rails Beginner - ruby-on-rails

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.

Related

how to update nested attribute in form

I wanna update the nested attribute but failed, for example there is a Article, and a book has many comments. when I find the comment I have written has some mistakes, so I wanna modify it.
here is my code.
In code_snippet.rb:
class CodeSnippet < ApplicationRecord
has_many :annotations, dependent: :destroy
accepts_nested_attributes_for :annotations ,update_only: true ,reject_if: :all_blank, allow_destroy: true
end
In annotation.rb:
class Annotation < ApplicationRecord
belongs_to :code_snippet
end
In code_snippet_controller.rb:
def edit
#code_snippet = CodeSnippet.find(params[:id])
end
def update
#code_snippet = CodeSnippet.find(params[:id])
if #code_snippet.update(code_snippet_params)
redirect_to #code_snippet
else
render 'edit'
end
end
private
def code_snippet_params
params.require(:code_snippet).permit(:snippet)
end
In annotation.rb:
def edit
#code_snippet = CodeSnippet.find(params[:code_snippet_id])
#annotation = #code_snippet.annotations.find(params[:id])
end
def update
#code_snippet = CodeSnippet.find(params[:id])
#annotation = #code_snippet.annotations.find(params[:id])
if #annotation.update(annotation_params)
redirect_to #code_snippet
else
render 'edit'
end
end
In 'views/code_snippets/show.html.rb'
<div>
<h2>Annotations</h2>
<%= render #code_snippet.annotations %>
</div>
In 'views/annotations/_annotation.html.erb'
<p>
<strong>User:</strong>
<%= annotation.user %>
</p>
<p>
<strong>Line:</strong>
<%= annotation.line %>
</p>
<p>
<strong>Body:</strong>
<%= annotation.body %>
</p>
<p>
<%= link_to "Edit", edit_code_snippet_annotation_path(annotation.code_snippet,annotation) ,controller: 'annotation'%>
</p>
In 'views/annotations/edit.html.erb':
<%= form_for(#code_snippet) do |f| %>
<%= f.fields_for :annotation,method: :patch do |builder| %>
<p>
<%= builder.label :user %><br>
<%= builder.text_field :user %>
</p>
<p>
<%= builder.label :line %><br>
<%= builder.text_field :line %>
</p>
<p>
<%= builder.label :body %><br>
<%= builder.text_area :body %>
</p>
<p>
<%= builder.submit %>
</p>
<% end %>
<% end %>
what I wanna update the annotation without change the codesnippets. what should I do to change my code.
So.... There's a lot going on here so I'm going to start by suggesting a careful look at the docs
Firstly, let's look at your form:
CodeSnippet has_many :annotations
So your fields_for statement should be for :annotations, not :annotation. The fields for statement also should not take a method options key.
Next your code_snippets_controller:
As indicated by the docs, the parameter sent back from the nested attributes form will be under the key: annotations_attributes and will contain a hash of arrays.
You need to allow this attribute, and any attribute you wish to pass onto the annotation model with strong parameters:
params.require(:code_snippet).permit(annotations_attributes: [:some, : permitted, :params])
I believe this is all you need to get your example working. But, if you run into more troubles, I recommend a spending some quality time with a few binding.pry statements to introspect on the actual behaviour of your code.

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

Nested model form with collection in Rails 2.3

How can I make this work in Rails 2.3?
class Magazine < ActiveRecord::Base
has_many :magazinepages
end
class Magazinepage < ActiveRecord::Base
belongs_to :magazine
end
and then in the controller:
def new
#magazine = Magazine.new
#magazinepages = #magazine.magazinepages.build
end
and then the form:
<% form_for(#magazine) do |f| %>
<%= error_messages_for :magazine %>
<%= error_messages_for :magazinepages %>
<fieldset>
<legend><%= t('new_magazine') %></legend>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<fieldset>
<legend><%= t('new_magazine_pages') %>
<% f.fields_for :magazinepages do |p| %>
<p>
<%= p.label :name %>
<%= p.text_field :name %>
</p>
<p>
<%= p.file_field :filepath %>
</p>
<% end %>
</fieldset>
<p>
<%= f.submit :save %>
</p>
</fieldset>
<% end %>
problem is, if I want to submit a collection of magazinepages, activerecord complaints because it's expected a model and not an array.
create action:
def create
#magazine = Magazine.new params[:magazine]
#magazine.save ? redirect_to(#magazine) : render(:action => 'new')
end
In magazine:
accepts_nested_attributes_for :magazinepages
Magazine.new(params[:magazine]) will then handle the object hierarchy for you automatically
I'm not 100% sure what you're asking, but if you're trying to instantiate a new magazine, with many magazinepages, you'll need to iterate over each magazine page. Something like this:
def create
#magazine = Magazine.new(params[:magazine])
if params[:magazinepages]
params[:magazinepages].each do |page|
#magazine.magazinepages.build(page)
end
end
# Save the model, do your redirection or rendering invalid model etc
end

How to create association for nested model in a form

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.

Resources