I'm doing a nested form in Rails 3.2.5, but when I add the accepts_nested_attributes_for my fields_for disappear (they just stop showing in my form).
This are my models:
class Product < ActiveRecord::Base
attr_accessible :title, :description, :variants_attributes
has_many :variants
accepts_nested_attributes_for :variants
validates :title, presence: true
end
My second model is
class Variant < ActiveRecord::Base
belongs_to :product
attr_accessible :price, :sku, :weight, :inventory_quantity, :product_id
end
And in my view I have
<%= form_for [:admin, #product], :html => {:multipart => true} do |f| %>
<%= render 'admin/shared/error_messages', object: f.object %>
<fieldset>
<legend>Producto Nuevo</legend>
<div class="control-group">
<%= f.label :title, 'Título', class: 'control-label' %>
<div class="controls">
<%= f.text_field :title %>
</div>
</div>
**<%= f.fields_for :variants do |variant| %>
<%= render 'inventory_fields', f: variant %>
<% end %>**
<div class="actions">
<%= f.submit 'Guardar', class: 'btn btn-primary' %>
</div>
<% end %>
_inventory_fields.html.erb
<div class="control-group">
<%= f.label :inventory_quantity, 'How many are in stock?', class: 'control-label' %>
<div class="controls">
<%= f.text_field :inventory_quantity, class: 'span1', value: '1' %>
</div>
</div>
The part between the ** is the one that is not being printed. And when I remove accepts_nested_attributes_for in my Product model fields_for start showing again but my form won't work.
What's happening?!?!
In the controller new action call
#product.varients.build
That should create 1 in memory varient in the product varient collection and it should bind to the fields for
Related
I have 2 models:
class Page < ApplicationRecord
enum page_type: STATIC_PAGE_TYPES, _suffix: true
has_one :seo_setting
accepts_nested_attributes_for :seo_setting, update_only: true
validates :title, :subtitle, length: { maximum: 50 }
validates :page_type, uniqueness: true
def to_param
"#{id}-#{page_type}".parameterize
end
end
and
class SeoSetting < ApplicationRecord
mount_uploader :og_image, SeoSettingsOgImageUploader
belongs_to :page
validates :seo_title, :seo_description, :og_title, :og_description, :og_image, presence: true
end
My Page objects are created from the seeds.rb file, and when I want to edit them, I get an error: Failed to save the new associated seo_setting.
In the form I have this:
<div class="card-body">
<%= form_for([:admin, #page]) do |f| %>
<%= render 'shared/admin/error-messages', object: #page %>
<div class="form-group">
<%= f.label :title, t('admin.shared.title') %>
<%= f.text_field :title, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :subtitle, t('admin.shared.subtitle') %>
<%= f.text_field :subtitle, class: 'form-control' %>
</div>
<h3>SEO Settings</h3>
<%= f.fields_for :seo_setting, f.object.seo_setting ||= f.object.build_seo_setting do |form| %>
<div class="form-group">
<%= form.label :seo_title, t('admin.shared.seo_title') %>
<%= form.text_field :seo_title, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :seo_description, t('admin.shared.seo_description') %>
<%= form.text_area :seo_description, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_title, t('admin.shared.og_title') %>
<%= form.text_field :og_title, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_description, t('admin.shared.og_description') %>
<%= form.text_area :og_description, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_image, t('admin.shared.og_image') %>
<div class="row">
<div class="col-lg-12">
<%= image_tag(form.object.og_image.url, style: 'width: 100px') if form.object.og_image? %>
</div>
</div>
<%= form.file_field :og_image %>
<%= form.hidden_field :og_image_cache %>
</div>
<% end %>
<div class="form-group">
<%= f.submit t('admin.actions.submit'), class: 'btn btn-success' %>
<%= link_to t('admin.actions.cancel'), admin_page_path(#page) , class: 'btn btn-default' %>
</div>
<% end %>
</div>
If I remove validations from my SeoSetting model, everything is working. It seems Rails doesn't like this part: f.object.build_seo_setting, because it creates a record in my database. Any ideas of how can I solve this issue? Thanks ahead.
Just had to change this line:
<%= f.fields_for :seo_setting, f.object.seo_setting ||= f.object.build_seo_setting do |form| %>
for this one:
<%= f.fields_for :seo_setting, #page.seo_setting.nil? ? #page.build_seo_setting : #page.seo_setting do |form| %>
Looks as if the problem lies here:
accepts_nested_attributes_for :seo_setting, update_only: true
in that you only allow the updating of the seo_setting on update.
Then, when you use this code:
f.object.seo_setting ||= f.object.build_seo_setting
You're falling back to a new seo_setting if the associated object is missing.
For this to work, you'll need to either remove the update_only: true, or only render the fields for the association if the seo_setting already exists.
Accepted answer, a conditional inside fields_for line, by OP, works also with polymorphic association and nested form (fields_for). Thnx Alex.
I am using cocoon gem for nested forms. My rails version is 4.2.6.
The association set between two models is as follows
Question.rb
class Question
include Mongoid::Document
field :title, type: String
has_many :choice_options, dependent: :destroy
accepts_nested_attributes_for :choice_options, :reject_if => :all_blank, :allow_destroy => true
validates :topic, presence: true
end
ChoiceOption.rb
class ChoiceOption
include Mongoid::Document
field :title, type: String
belongs_to :question
end
And I have new and question_params set as follows in questions controller
questions_controller.rb
class QuestionsController < ApplicationController
def new
#question = Question.new
end
private
def question_params
params.require(:question).permit(:title, choice_options_attributes: [:id, :title, :_destroy])
end
end
The partial form to create a new question and nested choice is as follows.
views/questions/_form.html.erb
<%= form_for #question do |f| %>
<%= render 'shared/errors', object: #question %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_area :title, rows: 3, required: true, class: 'form-control' %>
</div>
<div class="panel panel-default">
<div class="panel-heading">Options</div>
<div class="panel-body">
<%= f.fields_for :choice_options do |options_form| %>
<%= render 'choice_option_fields', f: options_form %>
<% end %>
<div class="links">
<%= link_to_add_association 'add option', f, :choice_options %>
</div>
</div>
</div>
<%= f.submit 'Create', class: 'btn btn-primary btn-lg' %>
<% end %>
And then I have created a partial form for choices which I am rendering in the above page.
views/questions/_choice_option_fields.html.erb
<div class="nested-fields">
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control', required: true %>
</div>
<%= link_to_remove_association "remove option", f %>
</div>
Now when I am trying to click the add option link from the partial form, its not appearing. the url is ending at
http://localhost:3000/questions/new#
You forgot to initiate the choice options in new
class QuestionsController < ApplicationController
def new
#question = Question.new
#question.choice_options.build
end
end
I have scoured all the other questions relating to this topic here, but I am still having this problem. I have a nested form inside a nested form. Answer choices are inside questions which are inside survey. I had no problem setting up the questions, and they save fine. The Answer choices, though, are not saving, and I cannot figure out where I am going wrong.
survey.rb
class Survey < ActiveRecord::Base
belongs_to :author
has_many :questions, dependent: :destroy
has_many :forms, dependent: :destroy
has_many :answer_choices, through: :question
validates :name, uniqueness: true
accepts_nested_attributes_for :questions, reject_if: proc { |attributes| attributes['text'].blank?},
allow_destroy: true
end
question.rb
class Question < ActiveRecord::Base
belongs_to :survey
has_many :responses, dependent: :destroy
has_many :answer_choices, dependent: :destroy
accepts_nested_attributes_for :answer_choices, reject_if: proc { |attributes| attributes['content'].blank?},
allow_destroy: true
end
answer_choice.rb
class AnswerChoice < ActiveRecord::Base
belongs_to :question
end
survey_controller.rb
def new
#survey = Survey.new(author_id: session[:user_id])
#survey.questions.build
#survey.questions.each { |question| 4.times { question.answer_choices.build }}
end
def edit
#survey.questions.build
#survey.questions.each { |question| 4.times { question.answer_choices.build }}
end
def survey_params
params.require(:survey).permit(:name, :description, :author_id,
questions_attributes: [:id, :text, :required, :response_type,
:_destroy, :number])
end
_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>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.hidden_field :author_id %>
</div>
<h2>Questions</h2>
<%= f.fields_for(:questions) do |ff| %>
<%= render 'questions', :f => ff %>
<% end %>
<div class="actions">
<%= f.submit 'Submit Question'%>
</div>
<div class="actions">
<%= link_to 'Finish Survey', surveys_path %>
</div>
<% end %>
_questions.html.erb
<div>
<span><%= f.index + 1 %>. </span>
<div class="field">
<%= f.hidden_field :number, value: f.index + 1 %>
</div>
<div class="field">
<%= f.label :text, "Question" %><br>
<%= f.text_field :text %>
</div>
<div class="field">
<%= f.label :response_type %><br>
<%= f.select :response_type, [["Yes/No", "yes/no"], ["Short Answer", "string"], ["Long Answer", "text"], ["Multiple Choice", "multi"]] %>
</div>
<div class="field">
<%= f.label :required %>
<%= f.check_box :required %>
</div>
<div>
<p>Answer Choices</p>
<%= f.fields_for(:answer_choices) do |ff| %>
<%= render 'answer_choices', :f => ff %>
<% end %>
</div>
<div class="field">
<%= f.label :_destroy %>
<%= f.check_box :_destroy %>
</div>
</div>
_answer_choices.html.erb
<div class="field">
<%= f.label :content %><br>
<%= f.text_field :content %>
</div>
<div class="field">
<%= f.label :_destroy %>
<%= f.check_box :_destroy %>
</div>
A few changes in your code.
Change your new method like this
def new
#survey = Survey.new(author_id: session[:user_id])
#questions = #survey.questions.build
#answer_choices = 4.times { #questions.answer_choices.build }
end
Your survey_params should look like this
def survey_params
params.require(:survey).permit(:name, :description, :author_id,
questions_attributes: [:id, :text, :required, :response_type,
:_destroy, :number, answer_choices_attributes: [:id,:content,:_destroy]])
end
And in your form code, change these lines
<%= f.fields_for(:questions) do |ff| %>
<%= f.fields_for(:answer_choices) do |ff| %>
into
<%= f.fields_for #questions do |ff| %>
<%= f.fields_for #answer_choices do |ff| %>
I want to create a nested form with relations between Clientes has_many enderecos, but in my form nothing is show up.
Look my models:
class Cliente < ActiveRecord::Base
has_many :enderecos, dependent: :destroy
validates :nome, :sexo, presence: true
validates :cpf, :email, :username, presence:true, uniqueness: true
has_secure_password
accepts_nested_attributes_for :enderecos
end
And endereco:
class Endereco < ActiveRecord::Base
belongs_to :cliente
end
And my form:
<%= form_for(#cliente) do |f| %>
<div class="field">
<%= f.text_field :nome, placeholder: 'Nome completo', size: '50px' %>
</div>
<% f.fields_for :endereco do |endereco_form| %>
<div class="field">
<%= endereco_form.label :cep, 'placeholder: ' %>
<%= endereco_form.text_field :cep, placeholder: 'CEP' %>
</div>
<div class="field">
<%= endereco_form.text_field :numero, placeholder: 'Número' %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
But inside nested part nothing is show up, what's happening?
You forgot the '=' sign:
<%= f.fields_for :endereco do |endereco_form| %>
I am trying to use :_destroy method in a nested form, but it just does not work
There are two models:
class Setting < ActiveRecord::Base
attr_accessible :category, :name, :setting_items_attributes, :_destroy
attr_accessor :_destroy
has_many :setting_items, :dependent => :destroy
accepts_nested_attributes_for :setting_items, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class SettingItem < ActiveRecord::Base
attr_accessible :setting_id, :value
belongs_to :setting
end
In the controller I create a instance:
def edit
#setting = Setting.find(params[:id])
#setting.setting_items.build
end
And the form looks like this:
<%= form_for(#setting) do |f| %>
<div class="field">
<%= f.label :category %>
<%= f.text_field :category %>
</div>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<hr>
<h3>Params:</h3>
<%= f.fields_for :setting_items do |s| %>
<span>
<div class="fields">
<%= s.text_field :value %>
<%= s.hidden_field :_destroy %>
<%= link_to_function "delete", "remove_fields(this)"%>
</div>
<% end %>
<div class="actions">
<%= f.submit "Update", :class => "btn btn-primary"%>
</div>
<% end %>
Also the function I use is here:
function remove_fields(link){
$(link).prev("input[type=hidden]").val("1");
$(link).parent().fadeOut("slow");
}
So the setting_items form is simply not working at all, It shows the update is successful, but nothing is actually added or deleted.
for example->your model associations are as follows: just follow the below steps to make use of magical _destroy attribute
####parent model
plan.rb
has_many :members,:dependent => :destroy
#this is important you want to destroy nested records
accepts_nested_attributes_for:members,:allow_destroy => true
attr_accessible :members_attributes
##child model
member.rb
belongs_to :plan
######controller
def edit
#plan.Plan.find(params[:id])
end
#####edit.html.erb
<%= form_for #plan do |f| %>
<%= f.fields_for :members do |member| %>
<div class="member">
<%= member.text_field :title%>
<%= image_tag 'delete.png',:class =>'remove_member',:id=>member.id %>
<!-- we need to set this hidden field value as 1 to mark it to be deleted during save/update of parent-->
<%= member.hidden_field :_destroy, :class => 'delete_member', :member_id => member.id %>
<!--similar to
<input id="plan_members_attributes_0__destroy" class="delete_member" type="hidden" value="false" name="plan[members_attributes][0][_destroy]" member_id="#{id of member}">
-->
</div>
<%end%>
<%end%>
##add js onclick of remove button/image
$('.delete_member').click(function(){
//remove div from screen
$(this).closest('.member').remove();
//get relevant id to remove/mark as delete
id =jQuery(this).attr('id');
//remove/mark the nested model/record as ready for deletion for rails by adding true/1 value
$("input[member_id="+id+"]").attr('value',1);
})