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.
Related
i made a nested form for my invoice application with the cocoon gem but the form isn't showing on my application but it isn't giving out any errors either.
_form.html.erb - scaffold form partial
<address>
<%= f.fields_for :customer do |customer| %>
<%= render 'customer_fields', f: customer %>
<%= link_to_add_association 'Add customer',f, :customer %>
<% end %>
</address>
_customer_fields.html.erb - cocoon partial
<div class="nested-fields">
<div class="form-group">
<%= f.label 'Company Name' %><br/>
<%= f.text_field :company_name, placeholder: 'company name' %>
</div>
<div class="form-group">
<%= f.label 'Address' %><br>
<%= f.text_field :address_line_1, placeholder: 'address' %>
</div>
<div class="form-group">
<%= f.label 'Zip Code' %><br>
<%= f.text_field :zip_code %>
</div>
<%= link_to_remove_association "remove customer", f, class: 'btn btn-primary' %>
</div>
Invoice.rb model
class Invoice < ActiveRecord::Base
has_one :company
has_one :customer
has_many :products
accepts_nested_attributes_for :customer, reject_if: :all_blank, allow_destroy: true
validates :number, :currency, :date, :duedate, :btwtotal, :subtotal, :total, presence: true
end
customer.rb model
class Customer < ActiveRecord::Base
belongs_to :invoice
end
Invoices_controller.rb
class InvoicesController < ApplicationController
before_action :set_invoice, only: [:show, :edit, :update, :destroy]
# GET /invoices
# GET /invoices.json
def index
#invoices = Invoice.all
end
# GET /invoices/1
# GET /invoices/1.json
def show
end
# GET /invoices/new
def new
#invoice = Invoice.new
end
# GET /invoices/1/edit
def edit
end
# POST /invoices
# POST /invoices.json
def create
#invoice = Invoice.new(invoice_params)
respond_to do |format|
if #invoice.save
format.html { redirect_to #invoice, notice: 'Invoice was successfully created.' }
format.json { render :show, status: :created, location: #invoice }
else
format.html { render :new }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /invoices/1
# PATCH/PUT /invoices/1.json
def update
respond_to do |format|
if #invoice.update(invoice_params)
format.html { redirect_to #invoice, notice: 'Invoice was successfully updated.' }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
# DELETE /invoices/1
# DELETE /invoices/1.json
def destroy
#invoice.destroy
respond_to do |format|
format.html { redirect_to invoices_url, notice: 'Invoice was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invoice
#invoice = Invoice.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invoice_params
params.require(:invoice).permit(:number, :currency, :date, :duedate, :btwtotal,
:subtotal, :total, :footer, customers_attributes: [:id, :company_name, :address_line_1, :zip_code, :_destroy],
companies_attributes: [:id, :btw_number, :iban_number, :kvk_number, :company_name, :_destroy])
end
end
Does anybody know how to fix this? Any help would be much much appreciated!
try it
<address>
<%= f.object.build_customer if f.object.customer.nil? %>
<%= f.fields_for :customer do |customer| %>
<%= render 'customer_fields', f: customer %>
<%= link_to_add_association 'Add customer',f, :customer %>
<% end %>
</address>
edit
in the Luissimo solution was missing to insert invoice_id in customer schema
rails generate migration AddInvoiceIdToCustomer invoice_id:integer
rake db:migrate
Invoice.first.build_customer
Looking at your original code, in your controller you should have added:
def new
#invoice = Invoice.new
#invoice.customer.build
end
Everything looks great as far as I can tell -- but the contents for the field_for nested form aren't displaying the 3 question forms I want. Why?
survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions
end
question.rb
class Question < ActiveRecord::Base
belongs_to :survey
end
surveys_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
end
# GET /surveys/1
# GET /surveys/1.json
def show
end
# GET /surveys/new
def new
#survey = Survey.new
3.times { #survey.questions.build }
end
# GET /surveys/1/edit
def edit
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:name)
end
end
surveys/new.html.erb
<h1>New Survey</h1>
<%= render 'form' %>
<%= link_to 'Back', surveys_path %>
surveys/_form.html.erb
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<% f.fields_for :questions do |builder| %>
<p>
<%= builder.label :content, "Question" %><br />
<%= builder.text_area :content, :rows => 3 %>
</p>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Can't believe I did this -- was missing <%= on fields_for
I am trying to run through a simple nested_attributes exercise, where a question has many answers (how like life is that?). I can't get the answers field to show up in either the 'new' or the 'edit' actions. As far as I can tell, I'm following the specs precisely. Clearly, this is not the case. Any pointers appreciated, thanks.
Models
# question.rb
has_many :answers
accepts_nested_attributes_for :answers
# answer.rb
belongs_to :question
View
# _form.html.erb
<%= form_for(#question) do |f| %>
...
<div class="field">
<%= f.label :content, 'Question' %><br>
<%= f.text_field :content %>
</div>
<div class="field">
<% f.fields_for :answers do |ff| %>
<%= ff.label :content, 'Answer' %><br>
<%= ff.text_field :content %>
<% end %>
</div>
...
<% end %>
Controller
# questions_controller.rb
def new
#question = Question.new
#question.answers.build
end
def edit
end
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
private
def question_params
params.require(:question).permit(:content, answer_attributes: [:id, :content, :question_id] )
end
Use <%=, not <%, otherwise the resulting output from the field_for Form Builder won't be output to the form.
<%= f.fields_for :answers do |ff| %>
Now I just need to figure out why the nested attribute (the answer)
isn't saving to the database.
Extending #Dylan Markow's answer.
Since it is has_many answers,it should be answers_attributes instead of answer_attributes in your question_params method.
def question_params
params.require(:question).permit(:content, answers_attributes: [:id, :content, :question_id] )
end
I'm having problem with some attributes which are not a part of my model. I'm trying to design a simple payment page as you can see below, all the fiels are represented in my database, except card_number and card_verification for security reasons.
When I load the page it is throwing an error:
undefined method `card_number' for #<Order:0x00000004eddb00>
undefined method `card_verification' for #<Order:0x00000004eddb00>
What's wrong with my form?
Thanks.
The Form:
<%= simple_form_for(#order, html:{class: "well"}) do |f| %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :card_type, collection: ["Visa", "MasterCard"] %>
<%= f.input :card_expires_on %>
<%= f.input :card_number %>
<%= f.input :card_verification %>
<%= f.button :submit %>
<% end %>
order.rb:
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :participation
end
orders_controller.rb:
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render action: 'show', status: :created, location: #order }
else
format.html { render action: 'new' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:ip_address, :first_name, :last_name, :card_type, :card_expires_on, :user_id, :participation_id)
end
end
I think the part that is throwing the error should be this in your form:
<%= f.input :card_number %>
<%= f.input :card_verification %>
You could try adding:
attr_accessor :card_number, :card_verification
to your model.
I tried to submit a new post and I get the error
"Title can't be blank"
So I removed the validations in my model and after trying again and posting something, the post is just blank, no data is saved whatsoever.
I don't know what to do, I stuck on this one, help!
Update!
Here is the form
<% #post.tags.build %>
<%= form_for #post, :html => {:multipart => true } do |post_form| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved: </h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= post_form.file_field :photo %>
</div>
<div class="field">
<%= post_form.label :title %><br />
<%= post_form.text_field :title %>
</div>
<div class="field">
<%= post_form.label :url %><br />
<%= post_form.text_field :url %>
</div>
<div class="field">
<%= post_form.label :company %><br />
<%= post_form.text_field :company %>
</div>
<div class="field">
<%= post_form.label :language %><br />
<%= post_form.text_field :language %>
</div>
<div class="field">
<%= post_form.label :framework %><br />
<%= post_form.text_field :framework %>
</div>
<div class="field">
<%= post_form.label :details %><br />
<%= post_form.text_area :details %>
</div>
<h2>Tags</h2>
<%= render :partial => 'tags/form' ,
:locals => {:form => post_form } %>
<div class="actions">
<%= post_form.submit %>
</div>
<% end %>
here is the controller:
class PostsController < ApplicationController
http_basic_authenticate_with :name => "franklinexpress", :password => "osxuser8", :except => [:index, :show, :new, :edit]
#def search
# #posts = Post.search(params[:search])
# end
# GET /posts
# GET /posts.json
def index
#posts = Post.search(params[:search])
# #posts = Post.all
# respond_to do |format|
#format.html # index.html.erb
#format.json { render json: #posts }
#end
end
# GET /posts/1
# GET /posts/1.json
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
# GET /posts/new
# GET /posts/new.json
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :ok }
end
end
end
in my model:
class Post < ActiveRecord::Base
validates :title, :presence => true
validates :url, :presence => true
validates :company, :presence => true
validates :language, :presence => true
validates_attachment_size :photo, :less_than => 4.megabytes
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png']
has_many :comments, :dependent => :destroy
has_many :tags
attr_accessor :photo_file_name
attr_accessor :photo_content_type
attr_accessor :photo_file_size
attr_accessor :photo_updated_at
attr_accessible :photo
accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
#paperclip-------------------------------
has_attached_file :photo,
:url => "/assests/images/:id/:style/:basename.:extension",
:path => ":rails_root/public/assets/images/:id/:style/:basename.:extension"
#:style => {:small => "150x200>"}
def self.search(search)
if search
where('title LIKE ?', "%#{search}%")
# find(:all, :conditions => ['title LIKE ?', "%#{search}%"])
else
all
end
end
end
and in new.html.erb:
<div id="header-wrap">
<%= image_tag("walLogotiny.png") %>
<div id="searchbartop">
<%= form_tag posts_path, :method => :get do%>
<%= text_field_tag :search, params[:search] ,"size" => 100 %>
<%= submit_tag "Search", :name => nil %>
<% end %>
</div>
</div>
<div id="container">
<h2>New Site Submission</h2>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>
</div>
With this line in your model:
attr_accessible :photo
You make only the photo attribute mass-assignable. All other attributes, including the title, are dropped when you create a new post.
Try this:
attr_accessible :photo, :title
It will now accept the title, but not the other attributes.
edit: didn't see your own comment above, but you figured it out already.