Hi i am trying to do the railcasts nested form, part 1 and part 2. It seem i am having several issues and I don't understand why.
Question 1: The add and remove links don't works, they show up but don't actually execute anything
Question 2: I get the following error code and don't understand why? The error is regarding the f.error_messages is not recognized
Question 3: When trying to create a surveys i get: Can't mass-assign protected attributes: answer
Thank you here my code similar to the railcasts 196,197
model question
class Question < ActiveRecord::Base
belongs_to :survey
attr_accessible :content, :question_id, :name, :answers_attributes
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers , :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
model answer
class Answer < ActiveRecord::Base
belongs_to :question
attr_accessible :content, :question_id
end
model surveys
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions , :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
attr_accessible :name, :questions_attributes
end
views
form
<%= form_for(#survey) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<p><%= link_to_add_fields "Add Question", f, :questions %></p>
<%= f.fields_for :questions do |bf|%>
<% render 'question_fields', :f => bf %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
question_fields
<p>
<%= f.label :content, "Question" %><br />
<%= f.text_area :content, :rows=> 3 %>
<%= f.check_box :_destroy %>
<%= link_to_remove_fields "remove", f %>
</p>
<p><%= link_to_add_fields "Add Answer", f, :answers %></p>
<%= f.fields_for :answer do |form| %>
<%= render 'answer_fields', :f => form %>
<% end %>
answer_fields
<p class="fields">
<%= f.label :content, "Answer" %>
<%= f.text_field :content %>
<%= link_to_remove_fields "remove", f %>
</p>
controller
javascript
application.js
function remove_fields(link) {
$(link).previous("input[type=hidden]").value = "1";
$(link).up(".fields").hide();
}
function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).up().insert({
before: content.replace(regexp, new_id)
});
}
application_jquery.js
function remove_fields(link) {
$(link).prev("input[type=hidden]").val("1");
$(link).closest(".fields").hide();
}
function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).parent().before(content.replace(regexp, new_id));
}
Any help is appreciated.
Here the link to the tutorial
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
And the route not sure what you mean.
Surveysays::Application.routes.draw do
resources :surveys
end
Question1: Those functions are not being called when you press the button. In the railscast he adds the link_to_remove and link_to_add to the application helper.
module ApplicationHelper
def link_to_remove_fields(name, f)
f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
end
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
render(association.to_s.singularize + "_fields", :f => builder)
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
end
end
Question 2: Not sure, but it might clear up with some of the other fixes
Question 3: You have a type here:
<%= f.fields_for :answer do |form| %>
<%= render 'answer_fields', :f => form %>
<% end %>
Should be
<%= f.fields_for :answers do |form| %>
<%= render 'answer_fields', :f => form %>
<% end %>
It's answers because you have a has_many relations ship. The attribute answer doesn't exist and is also whitelisted by default. That's why you get mass assignment errors.
Also there is a simpler version of this in his revised episode:
http://railscasts.com/episodes/196-nested-model-form-revised
Related
Order has_many jobs
Job belongs to order
And I want to edit attributes of #job.order:
<% order = #job.order %>
<%= simple_form_for [#job, order],
url: job_path(#job),
method: :put,
remote: true do |f| %>
<%= f.input :order_status, input_html: {class: 'form-control'} %>
(...)
<% end %>
any way to do it by just using input in simple form?
in job.rb
accepts_nested_attributes_for :order
in form.html.erb
simple_form_for #job do |f|
f.simple_fields_for #job.order do |order_form|
order_form.input :status
end
end
in jobs_controller.rb
params.require(:job).permit(:something, :something_else, :order_attributes => [:status])
You can use the excellent Cocoon gem https://github.com/nathanvda/cocoon to manage nested relationships, including the ability to easily add new nested relationships.
class Job < ActiveRecord::Base
has_many :orders
accepts_nested_attributes_for :orders, reject_if: :all_blank, allow_destroy: true
end
class Order < ActiveRecord::Base
belongs_to :job
end
Note the pluralization.
_form.html.erb*
<%= form_for #job do |f| %>
<%= f.label :job_name %>
<%= f.text_field :name %>
<div id='order'>
<%= f.fields_for :orders do |order| %>
<%= render 'order_fields', f: order %>
<% end %>
<div class='links'>
<%= link_to_add_association 'add order', f, :orders %>
</div>
<%= f.submit %>
<% end %>
_order_fields.html.erb partial
<div class='nested-fields'>
<%= f.label :order_name %>
<%= f.text_field :order_name %>
</div>
<%= link_to_remove_association "remove order", f %>
Hi all. When I open /courses/new (or /courses/some_id/edit), browser returns this error:
Showing /app/views/dashboard/courses/_price.html.erb where line #1 raised:
undefined method `label' for nil:NilClass
Here are codes, _form.html.erb:
<%= simple_form_for [:dashboard, #course], html: { multipart: true } do |f| %>
//////
<%= f.fields_for :prices do |p|%>
<%= render 'price', :f => 'prices' %>
<% end %>
<%= link_to_add_association 'Add', f, :prices %>
////////
_price.html.erb:
<%= p.label :price %>
<%= p.text_field :price %>
<%= p.label :desc %>
<%= p.text_field :description %>
<%= link_to_remove_association "remove", f %>
Models:
class Price < ActiveRecord::Base
belongs_to :course
end
class Course < ActiveRecord::Base
has_many :prices
accepts_nested_attributes_for :prices, :reject_if => :all_blank, :allow_destroy => true
end
How resolve this error? And why it has arisen?
You are using simple_form_for,so i guess this line
<%= f.fields_for :prices do |p|%>
should be
<%= f.simple_fields_for :prices do |p|%>
Have a look at the Git for more Info.
In your _price.html.erb partial view, your are using a form builder that does not exists (is nil) because you did not pass it as argument:
# _price.html.erb
<%= p.label :price %>
#^ the variable `p` is the form builder here
To solve this problem, you have to pass the form builder to the partial view, like this:
<%= f.fields_for :prices do |p| %>
<%= render 'price', :f => 'prices', p: p %>
#^^^^ We pass the variable `p` (form builder) to the partial
<% end %>
Hope this helps!
I have a three models Report,Question,Answer
Answer
belong_to :question
Question
belong_to :reports
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :allow_destroy => true
Reports
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :allow_destroy => true
While creating a new report some questions are randomly picked to be added to the report and show form in this way :
Report Form
<%= form_for #report do |f| %>
<div class="field">
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :f => builder %>
<% end %>
</div>
<div class="actions">
<%= f.submit "Submit Report"%>
</div>
<% end %>
---Partial Question_Fields---
<h4 class="question_name">
<%= f.object.name %>
</h4>
<%= f.fields_for :answers do |answer,index| %>
<%= render 'answer_fields', :f => answer %>
<% end %>
---Partial Answer_Fields---
<%= f.text_field :name, :placeholder => "Add your answer here" %>
But when I try to edit/create a new report it fetches all the existing answers for that particular question. Whereas I want to implement something like :
---Partial Question_Fields---
<h4 class="ques_title">
<%= f.object.name %>
</h4>
<% f.object.answers_for_report(#report).each do |answer| %>
<%= render 'answer_fields', :f => answer %>
<% end %>
---Partial Question_Fields---
<b>What should be code here so that it again acts same as nested attributes and gets updated succesfully !!!</b>
Question Model
belong_to :reports
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :allow_destroy => true
def answers_for_report(#report)
self.answers.where("report_id = ? ",report.id)
end
Here is the answer to my question :
Report Form is like
<%= form_for #report do |f| %>
<div class="field">
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :f => builder %>
<% end %>
</div>
<div class="actions">
<%= f.submit "Submit Report"%>
</div>
<% end %>
Then Question 'question_fields' is like
<%= question.fields_for :answers, question.object. answers_for_report(#report) do |answer| %>
<%= render 'answer_fields', :f => answer %>
<% end %>
This passes only a collections / set of records of answers and renders fields for those selected answers only.
I have an error "Can't mass-assign protected attributes: Upload", but I have assigned it to be accessible.
This is a nested form with a polymorphic association.
Models
class Upload < ActiveRecord::Base
attr_accessible :link, :post_id
belongs_to :uploadable, polymorphic: true
end
class Post < ActiveRecord::Base
attr_accessible :description, :title, :uploads_attributes
has_many :uploads, as: :uploadable
accepts_nested_attributes_for :uploads, :reject_if => lambda { |a| a[:content].blank?
}, :allow_destroy => true
end
I tried too put accept_nested ... for :uploadable but tells me dont exist the association
The action new on the controller is this one
def new
#post = Post.new
#post.uploads.new
end
and here is the form for create
<%= form_for [:admin,#post], remote: true, :html => {:multipart => true} do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title%>
</div>
<div class="field">
<%= f.label :description%><br />
<%= f.text_area :description %>
</div>
<div>
<%= f.fields_for :upload do |builder| %>
<%= render 'upload_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Upload", f, :uploads %>
</div>
<div class="actions">
<%= f.submit%>
</div>
<% end %>
The partial ...
<fieldset>
<%= f.label :file %><br />
<%= f.file_field :file %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Dont think the javascript affects, so Im not going to put it here.
How I cna solve "Can't mass-assign protected attributes" on polymorphic asociations ?
Plz need help on this anyone. Cant belive I cant upload files, looks so simple on tutorials, and Its not working, or I get a Can't mass assign orthe upload its not saved ....
Try to use #post.uploads.build instead of #post.uploads.new
The associated model needs to know the identity of her parent to save the relationship.
I recommend you the following railscast: Polymorphic Association.
#uploads_controller.rb
before_filter :load_uploadable
def create
#upload = #uploadable.uploads.new(params[:upload])
....
end
private
def load_uploadable
resource, id = request.path.split('/')[1, 2] # /posts/1
#uploadable = resource.singularize.classify.constantize.find(id)
end
This line inside your view:
<%= f.fields_for :upload do |builder| %>
Should be this:
<%= f.fields_for :uploadable do |builder| %>
Because the association on the Post model is called "uploadable", not "upload".
For nested attributes to work, you will need to specify the model does accept nested attributes for this model, which can be done by putting this line underneath the belongs_to in your model:
accepts_nested_attributes_for :uploadable
And then you will need to make these attributes accessible, which you can do with this:
attr_accessible :uploadable_attributes
I'm trying to make a dynamic form of questions and answers, like so:
Question _______
Answer _______
Question _______
Answer _______
I can't figure out how to loop through the two resources as alternating pairs. I have tried this:
<%= semantic_fields_for [#question, #answer] do |h, i| %>
<%= f.inputs :for => #question do |h|%>
<%= h.input :question %>
<% end %>
<%= f.inputs :for => #answer do |i|%>
<%= i.input :answer %>
<% end %>
<% end %>
But it gives me the error "Undefined method `model_name' for Array:Class."
My controller:
def new
#post = Post.new
#question = #post.questions.new
#answer = #question.build_answer
respond_to do |format|
format.html
end
end
And my models:
class Post < ActiveRecord::Base
has_many :questions
has_many :answers
end
class Question < ActiveRecord::Base
belongs_to :post
has_one :answer
end
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :post
end
So I don't personally use formtastic but I understand it follows similar lines to simple_form. Your error is coming from trying to pass an Array to semantic_fields_for which only takes a single object:
<%= semantic_form_for #questions do |q| %>
<%= q.input :question %>
<%= q.semantic_fields_for #answer do |a| %>
<%= a.inputs :answer %>
<% end %>
<%= q.actions %>
<% end %>
Don’t forget your models need to be setup correctly with accepts_nested_attributes_for
class Question < ActiveRecord::Base
belongs_to :post
has_one :answer
accepts_nested_attributes_for :answers
end
You'll want to check out the formtastic docs at https://github.com/justinfrench/formtastic
That should get your form showing correctly in the view but you'll need to add some more to your questions controller to make sure it saves the answers (someone correct me if I'm mistaken).
Also just so it's clear do your Questions and Answers tables really have a question and answer column? If the columns are actually something like :body you'll want to replace the relevant symbols in the above code.
I think what you need is exactly what is described in these railcasts:
Nested Model Form Part 1
Nested Model Form Part 2
I think you should also refactor a bit, Posts should not have questions. You might notice a little difference from the railcasts but that's because you have only one answer per question whereas in the railcasts a question has many answers. In the part 2 it shows how to add AJAX calls to add/remove questions and answers (probably you won't need this if you only have one answer).
Mandatory reading so you have a better understanding of associations and how nested attributes work:
A Guide to Active Record Associations
Active Record Nested Attributes
And this is an example that will probably work, with some minimum tweaking. I haven't used semantic fields, just the standard form builder.
class Post < ActiveRecord::Base
has_many :questions
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class Question < ActiveRecord::Base
belongs_to :post
has_one :answer, :dependent => :destroy
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class Answer < ActiveRecord::Base
belongs_to :question
end
# posts_controller.rb
def new
#post = Post.new
# lets add 2 questions
2.times do
question = #post.questions.build
question.build_answer
respond_to do |format|
format.html
end
end
# views/posts/_form.html.erb
<%= form_for #post do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :f => builder %>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
# views/posts/_question_fields.html.erb
<p>
<%= f.label :content, "Question" %><br />
<%= f.text_area :content, :rows => 3 %><br />
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Question" %>
</p>
<%= f.fields_for :answers do |builder| %>
<%= render 'answer_fields', :f => builder %>
<% end %>
# views/posts/_answer_fields.html.erb
<p>
<%= f.label :content, "Answer" %>
<%= f.text_field :content %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove" %>
</p>