The fields_for block doesn't output in a has_many relationship. This problem came up in a somewhat involved project I was working on. I broke it down to a very simple test case, but it still doesn't work. This question has been asked before and the problem was usually
that the nested object didn't exist. But here, the nested object does appear to exist, as explained in the code comments. I'm pretty new to rails so it could be something obvious.
Here is the simple case model code:
class Parent < ActiveRecord::Base
has_many :children
accepts_nested_attributes_for :children
end
class Child < ActiveRecord::Base
belongs_to :parent
end
Simple case controller:
class ParentController < ApplicationController
def index
#parent = Parent.find_by_id(1)
end
end
Simple case view:
<%= form_for #parent, {:url=>{:action=>:index}} do |f| %>
<!-- this outputs ok -->
<%= f.text_field :name %>
<% f.object.children.each do |c| %>
<!-- this outputs "child1", so the nested object exists -->
<%= c.name %>
<% f.fields_for c do |field| %>
this line does NOT output, nor does the field below
<%= field.text_field :name %>
<% end %>
<% end %>
<% end %>
I also tried this and saw the same result:
<%= form_for #parent, {:url=>{:action=>:index}} do |f| %>
<%= f.text_field :name %>
output here
<% f.fields_for :children do |field| %>
no output here nor the field below
<%= field.text_field :name %>
<% end %>
<% end %>
I also tried with a new #parent object in the controller and a #parent.build_child
(having changed the assoc to a has_one). That still saw the same result.
You've forgotten to put the = sign after <%.
Replace:
<% f.fields_for :children do |field| %>
with:
<%= f.fields_for :children do |field| %>
Related
I have problem adding a nested model to a form. Specifically, nothing appears in this form section.
new.html.erb
<%= render 'form' %>
_form.html.erb
...
<% fields_for :bigip do |f| %>
<%= f.text_field :bgname %>
<%= f.text_field :bguser %>
<%= f.text_field :bgpassword %>
<% end %>
...
Here are the underlying models and controllers.
pool.rb
class Pool < ApplicationRecord
has_one :bigip, inverse_of: :pool
accepts_nested_attributes_for :bigip, :allow_destroy => true
end
bigip.rb
class Bigip < ApplicationRecord
belongs_to :pool
end
pools_controller.rb
def new
#pool = Pool.new
#pool.build_bigip
end
devil is in details :)
I simply missed "=" in line "<% fields_for :bigip do |f| %>"
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.
I am currently trying to make a form for a model, which has a dynamic number of nested models. I'm using Nested Forms (as described in RailsCasts 197). To make things even more complicated, each of my nested models has a has_one association with a third model, which I would also like to be added to the form.
For any who are wondering about over normalization or an improper approach, this example is a simplified version of the problem I'm facing. In reality, things are slightly more complex, and this is the approach we've decided to take.
Some example code to illustrate the problem below:
#MODELS
class Test
attr_accessible :test_name, :test_description, :questions_attributes
has_many :questions
accepts_nested_attributes_for :questions
end
class Question
attr_accessible :question, :answer_attributes
belongs_to :test
has_one :answer
accepts_nested_attributes_for :answer
end
class Answer
attr_accessible :answer
belongs_to :question
end
#CONTROLLER
class TestsController < ApplicationController
#GET /tests/new
def new
#test = Test.new
#questions = #test.questions.build
#answers = #questions.build_answer
end
end
#VIEW
<%= form_for #test do |f| %>
<%= f.label :test_name %>
<%= f.text_box :test_name %>
<%= f.label :test_description %>
<%= f.text_area :test_description %>
<%= f.fields_for :questions do |questions_builder| %>
<%= questions_builder.label :question %>
<%= questions_builder.text_box :question %>
<%= questions_builder.fields_for :answer do |answers_builder| %>
<%= answers_builder.label :answer %>
<%= answers_builder.text_box :answer %>
<% end %>
<% end %>
<%= link_to_add_fields 'New', f, :questions %>
<% end %>
This code example works fully for the first instance of Question. The issue occurs when another question is dynamically added to be created; the answer fields are not displayed. I believe this is because they are only built for the first question in the controller. Is there a way to achieve this using nested_attributes?
I solved my own issue here. What I did was, instead of building the answer model in the controller (which is impossible when you do not know how many questions are going to be made in the view), I built it when calling fields_for:
#CONTROLLER
class TestsController < ApplicationController
#GET /tests/new
def new
#test = Test.new
#questions = #test.questions.build
end
end
#VIEW
<%= form_for #test do |f| %>
<%= f.label :test_name %>
<%= f.text_box :test_name %>
<%= f.label :test_description %>
<%= f.text_area :test_description %>
<%= f.fields_for :questions do |questions_builder| %>
<%= questions_builder.label :question %>
<%= questions_builder.text_box :question %>
<%= questions_builder.fields_for :answer, #questions.build_answer do |answers_builder| %>
<%= answers_builder.label :answer %>
<%= answers_builder.text_box :answer %>
<% end %>
<% end %>
<%= link_to_add_fields 'New', f, :questions %>
<% end %>
This works because no matter how many question forms are being built on the view, a new answer specific to the question being built is built.
i´m a newbie to rails and have a problem with my associated object not being saved. I think I did everything the way it should be done and I can´t figure out, why it isn´t working. So thanks in advance for everyone who can help me get a little closer to solving this problem.
These are my models :
class Examdate < ActiveRecord::Base
belongs_to :exam
attr_accessible :date, :exam_id
end
class Exam < ActiveRecord::Base
attr_accessible :title, :prof_id, :deadline
belongs_to :prof
has_many :examdates, :dependent => :destroy
accepts_nested_attributes_for :examdates
end
In my exams_controller I have this:
def new
#exam = Exam.new
3.times{#exam.examdates.build()}
end
def create
#exam = Exam.new(params[:exam])
respond_to do |format|
if #exam.save
....
Now in my view I have the semantic_fields_for method, I also tried it with normal fields_for and got the same result:
<%= semantic_form_for #exam do |f| %>
<% if #exam.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#exam.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #exam.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.inputs do%>
<%= f.input :title%>
<%= f.input :prof%>
<%= f.input :deadline, :start_year => Time.now.year, :label => "Anmeldefrist"%>
<% end %>
<%= f.semantic_fields_for :examdates do |builder|%>
<%= render "examdates_fields", :f => builder %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button "Speichern"%>
<% end %>
<% end %>
In the partial is this, will later be extended
<%= f.inputs :date%>
Now I get the form with the correct three date fields and I can save the Exam itself correctly. When I look at params[:exam][:examdates_attributes] the dates are there:
{"0"=>{"date(1i)"=>"2006", "date(2i)"=>"1", "date(3i)"=>"1"},
"1"=>{"date(1i)"=>"2006", "date(2i)"=>"1", "date(3i)"=>"1"},
"2"=>{"date(1i)"=>"2006", "date(2i)"=>"1", "date(3i)"=>"1"}}
But when I put Exam.find(1).exdates in my rails Console, I get []. I really don´t have any idea what I did wrong, so every little tip is very appreciated:)
Since you are using attr_accessible in your Exam model, I think you'll have to include :examdates_attributes in that list. Otherwise, mass assignment to the nested model will not be allowed.
class Exam < ActiveRecord::Base
attr_accessible :title, :prof_id, :deadline, :examdates_attributes
...
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 %>