I have a form that save a question and five answers in the database but I don't know how I can save the answers, this is my form:
<%= form_for([:admin, #question]) do |f| %>
...
<%= f.fields_for :answers do |builder| %>
<%= builder.label :answer, "Risposta", :class => "v-align" %>
<%= builder.text_field :answer, :rows => 2 %>
<%= builder.label :correct, "Corretta", :class => "v-align" %>
<%= builder.check_box :correct %>
<% end %>
...
<% end %>
My models:
class Question < ActiveRecord::Base
has_many :answers
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
attr_accessible :answers_attributes, :quiz_id, :question, :sort_order, :point_value, :number_correct, :explanation
end
class Answer < ActiveRecord::Base
belongs_to :question
attr_accessible :question_id, :answer, :correct, :sort_order
end
And my "Question" controller:
def new
#question = Question.new
5.times { #question.answers.build }
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #question }
end
end
def create
#question = Question.new(params[:question])
respond_to do |format|
if #question.save
format.html { redirect_to admin_question_path(#question), :notice => 'Test was successfully created.' }
format.json { render :json => #question, :status => :created, :location => #question }
else
format.html { render :action => "new" }
format.json { render :json => #question.errors, :status => :unprocessable_entity }
end
end
end
What I should do to save question and answer in the database?
Thanks!!
You only miss accepts_nested_attributes_for :answersin the Question model.
See doc.
EDIT:
You should add answers_attributes to your attr_accessible list
You should take a look at two RailsCasts:
http://railscasts.com/episodes/196-nested-model-form-part-1 and http://railscasts.com/episodes/197-nested-model-form-part-2
They might help you a lot!
The man behind those casts, Ryan Bates, created a great gem to handle nested forms!
Related
I am new to rails and keep struggling with the following issue. Unfortunately, hours of search have not led to a solution, so I would be more than happy to get your input.
On creating an order, I attempt to create a client (as parent) and order items (as child). The latter works fine. However, on saving the order, both order and client are stored in the database with the exception that the *client_id* is not passed to the order record.
Here follows my code:
Company Model
class Company < ActiveRecord::Base
has_many :orders, foreign_key: "client_id"
accepts_nested_attributes_for :orders
validates :name,
:presence => true,
:uniqueness => { :case_sensitive => false }
validates_associated :users,
:orders
attr_accessible :name,
:account,
:users_attributes,
:orders_attributes,
:company_id
end
Order Model
class Order < ActiveRecord::Base
has_many :order_items
accepts_nested_attributes_for :order_items
belongs_to :client, class_name: "Company",
foreign_key: "id"
accepts_nested_attributes_for :client
attr_accessible :order_items_attributes,
:order_number,
:client_attributes,
:client_id
validates_associated :order_items
validates_presence_of :order_number
:client_id
end
Orders Controller
def create
#order = #client.orders.build(params:[orders])
puts #order.to_yaml
respond_to do |format|
if #order.save!
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render json: #order, status: :created, location: #order }
else
format.html { render action: "new" }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
New Order Form
<%= simple_form_for #order, :html => { :class => 'form-horizontal' } do |f| %>
<%= render 'shared/error_messages', :object => #order %>
<div class = "span3">
<%= f.simple_fields_for :client do |client_builder| %>
<%= client_builder.input :name,
:label => 'Client' %>
<% end %>
<%= f.input :order_number %>
<%= f.simple_fields_for :order_items do |items_builder| %>
<%= items_builder.input :reference_number %>
<%= items_builder.input :item_description %>
<% end %>
<%= f.button :submit,
:class => 'btn'%>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
orders_path, :class => 'btn' %>
</div>
<% end %>
Thanks for your help in advance!
Stefan
belongs_to :client, class_name: "Company", foreign_key: "id"
Should be
belongs_to :client, class_name: "Company", foreign_key: "client_id"
Also i would update your migration and make that field not nullable, better to get an exception than saving an order without client
I understand some railscasts may be old, but revised shouldn't be. I am trying really hard to overcome nested form, but most answer i get is use a plugin. So i try to make the railcasts from scratch but an exception occurs. I am wondering what would be the Railcasts 196 Updated Version has today with proper code.
Here my code, maybe its a silly mistake from me.
Survey Model
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
Question Model
class Question < ActiveRecord::Base
belongs_to :survey
attr_accessible :content, :question_id
accepts_nested_attributes_for :answers , :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
attr_accessible :name, :answers_attributes
end
Answer Model
class Answer < ActiveRecord::Base
belongs_to :questions
attr_accessible :content, :question_id
end
Survey Show Form
<p id="notice"><%= notice %></p>
<div>Name:</div>
<div><%=#survey.name%></div>
<% for question in #survey.questions %>
<div><%=h question.content%></div>
<% end %>
<%= link_to 'Edit', edit_survey_path(#survey) %> |
<%= link_to 'Back', surveys_path %>
Form.html.erb
<%= form_for(#survey) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |bf|%>
<% render 'question_fields, :f => bf %>
<% end %>
***<div class="actions">***
<%= f.submit %>
</div>
<% end %>
question_field Form
<%= f.label :content, "Question" %><br />
<%= f.text_area :content, :rows=> 3 %><br />
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Question"%><br />
<%= f.fields_for :answer do |form| %>
<%= render 'answer_fields', :f => form %>
<% end %>
answer_field Form
<%= f.label :content, "Answer" %>
<%= f.text_field :content %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove" %>
Survey Controller
class SurveysController < ApplicationController
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #surveys }
end
end
# GET /surveys/1
# GET /surveys/1.json
def show
#survey = Survey.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #survey }
end
end
# GET /surveys/new
# GET /surveys/new.json
def new
#survey = Survey.new
3.times {#survey.questions.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #survey }
end
end
# GET /surveys/1/edit
def edit
#survey = Survey.find(params[:id])
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(params[:survey])
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render json: #survey, status: :created, location: #survey }
else
format.html { render action: "new" }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PUT /surveys/1
# PUT /surveys/1.json
def update
#survey = Survey.find(params[:id])
respond_to do |format|
if #survey.update_attributes(params[:survey])
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey = Survey.find(params[:id])
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url }
format.json { head :no_content }
end
end
end
Here my error when creating a new survey
Not sure what else could be wrong
ArgumentError in SurveysController#create
No association found for name `answers'. Has it been defined yet?
Here the new error
SyntaxError in Surveys#new
Showing /home/jean/rail/surveysays/app/views/surveys/_form.html.erb where line #22 raised:
/home/jean/rail/surveysays/app/views/surveys/_form.html.erb:22: syntax error, unexpected keyword_class, expecting keyword_do or '{' or '('
#output_buffer.safe_concat(' <div class="actions">
^
/home/jean/rail/surveysays/app/views/surveys/_form.html.erb:24: unterminated regexp meets end of file
/home/jean/rail/surveysays/app/views/surveys/_form.html.erb:24: syntax error, unexpected $end, expecting keyword_end
Add has_many :answers to the Question model and change the Answer model to belongs_to :question.
I have 3 model the first user.rb:
class User
has_many :boards, dependent: :destroy
has_many :posts, dependent: :destroy, :autosave => true
accepts_nested_attributes_for :boards
accepts_nested_attributes_for :posts
end
The second model its board.rb
class Board
has_many :posts, :dependent => :destroy , :autosave => true
accepts_nested_attributes_for :posts
belongs_to :user
end
The third model its post.rb
class Post
belongs_to :user
belongs_to :board
end
I want create a new post with a parent board in my action new from posts_controllers I have:
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
I create a new board with:
def create
#board = current_user.boards.new(params[:board])
respond_to do |format|
if #board.save
format.html { redirect_to #board, notice: 'Board was successfully created.' }
format.json { render json: #board, status: :created, location: #board }
else
format.html { render action: "new" }
format.json { render json: #board.errors, status: :unprocessable_entity }
end
end
end
In partial _form.thml.erb I have this:
<%= form_for(#post, :html => {:multipart => true}) do |f| %>
<%= f.label :content %><br />
<%= f.text_area :content %>
<%= f.collection_select :board_id, Board.all, :id, :name%>
<%= f.submit %>
<% end %>
The problem is that in my select field appear every boards. I want only show and choose the boards that belongs_to the current_user.
Note I'm using mongoid.
Your model can be simpler.
class User
has_many :boards, dependent: :destroy
accepts_nested_attributes_for :boards
end
class Board
has_many :posts, :dependent => :destroy , :autosave => true
belongs_to :user
accepts_nested_attributes_for :posts
end
class Post
belongs_to :board
end
<%= form_for(#post, :html => {:multipart => true}) do |f| %>
<%= f.label :content %><br />
<%= f.text_area :content %>
<%= f.collection_select :board_id, Board.find_by_user_id(current_user.id), :id, :name%>
<%= f.submit %>
<% end %>
This is my hacked together attempt at getting Carrierwave to work right from watching Railscast. I have a Post Project page where users enter in details for a project. They can also upload a file to this page, and submit the project. So I am using a nested_form_for on the page.
new_step_3.html.erb
<%= nested_form_for #project, :html => {:multipart => true} do |f| %>
<%= f.text_field :title %>
<%= f.text_field :description %>
<%= f.fields_for :document do |attachment_form| %>
<%= attachment_form.file_field :title %>
<% end %>
<%= f.text_field :skills %>
<%= f.submit 'Post Project' %>
<% end %>
project.rb model
attr_accessible :category, :title, :budget, :end_date, :description, :skills, :document, :days_lasting, :documents_attributes
belongs_to :user
has_many :posts
has_many :documents, :as => :attachable
validates_presence_of :category, :title, :description, :skills
accepts_nested_attributes_for :documents
document.rb model
attr_accessible :project_id, :title, :document
belongs_to :user
belongs_to :project
has_many :posts
mount_uploader :document, DocumentUploader
projects_controller.rb
def create
#project = current_user.projects.build(params[:project])
respond_to do |format|
if #project.save
format.html { redirect_to project_step_4_path(:start => #project.id), notice: 'Project was successfully created.' }
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
Right now, when I try to submit the form, it will say unknown attribute: document
app/controllers/projects_controller.rb:85:in `create'
Running the command in Rails console works Document.create!(:document => File.new("test.jpg"))
I think it should be
<%= f.fields_for :documents do |attachment_form| %>
<%= attachment_form.file_field :title %>
<% end %>
with fields_for :documents
That's why it's not finding the document attribute. Your form probably sends a hash like that:
{
:project => {
:title => "blabla",
:document => {...}
}
}
and it doesnt know what to do with the document.
Now your nested documents will be in :documents => {}, and with the accepts_nested_attributes_for, it should work.
You have to build a document for this project in the controller:
#project.documents.build
I have two models, links and tags, associated through a third, link_tags. The following code is in my Link model.
Associations:
class Link < ActiveRecord::Base
has_many :tags, :through => :link_tags
has_many :link_tags
accepts_nested_attributes_for :tags, :allow_destroy => :false,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end
class Tag < ActiveRecord::Base
has_many :links, :through => :link_tags
has_many :link_tags
end
class LinkTag < ActiveRecord::Base
belongs_to :link
belongs_to :tag
end
links_controller Actions:
def new
#link = #current_user.links.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #link }
end
end
def create
#link = #current_user.links.build(params[:link])
respond_to do |format|
if #link.save
flash[:notice] = 'Link was successfully created.'
format.html { redirect_to links_path }
format.xml { render :xml => #link, :status => :created, :location => #link }
else
format.html { render :action => "new" }
format.xml { render :xml => #link.errors, :status => :unprocessable_entity }
end
end
end
View code from new.html.erb:
<% form_for [current_user, #link], :url => account_links_path do |f| %>
<%= render :partial => "form", :locals => { :f => f } %>
<% end %>
And the corresponding partial:
<%= f.error_messages %>
<p>
<%= f.label :uri %><br />
<%= f.text_field :uri %>
</p>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<h2>Tags</h2>
<% f.fields_for :tags_attributes do |tag_form| %>
<p>
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</p>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<p>
<%= tag_form.label :_delete, 'Remove:' %>
<%= tag_form.check_box :_delete %>
</p>
<% end %>
<% end %>
<p>
<%= f.submit 'Update' %>
</p>
The following line of code, in the create action in the Link controller throws an error:
#link = #current_user.links.build(params[:link])
The error: Tag(#-621698598) expected, got Array(#-609734898)
Are there additional steps needed in the has_many => :through case? These seem to be the only indicated changes for the basic has_many case.
Take a look at the line of your code
<% f.fields_for :tags_attributes do |tag_form| %>
You need to use just :tags instead of :tags_attributes.
This will solve your issue
Make sure that You have build links and tags in your controller like
def new
#link = #current_user.links.build
#link.tags.build
end
I found this here on stackoverflow:
Rails nested form with has_many :through, how to edit attributes of join model?
please tell me if it worked.
In order for this to work, you need to pass in the right params hash:
params = {
:link => {
:tags_attributes => [
{:tag_one_attr => ...}, {:tag_two_attr => ...}
],
:link_attr => ...
}
}
And your controller will look like:
def create
#link = Link.create(params[:link]) # this will automatically build the rest for your
end
Try this:
<% f.fields_for :tags_attributes do |tag_form| %>
In your controller in the new action (that loads the form partial), are you building a #tag through your link?
So you should see something along the lines of:
#link = Link.new
#tag = #link.tags.build
It might be best to post the contents of the new and create action of your links_controller.
try
<% f.fields_for :tags do |tag_form| %>
(ie lose the _attributes in :tag_attributes) That's how I've usually done nested forms
You need to build a tag in your controller or in the view
def new
#link = #current_user.links.build
#link.tags.build
end
#in your view you can just use the association name
<% f.fields_for :tags do |tag_form| %>