Having issues with nested attributes using fields_for. Anyone know what I am missing? I have checked many posts and RailsCasts and have not been able to figure it out.
Overview: I have a list of chart types (chart_type) that have one or more parameters (chart_param). Based on the chart type selected, I display the proper chart parameters and allow users to enter a value (chart_param_value). This is all from within my Indicators form.
Problem: The form submission is not retuning the nested attributes properly. The params being submitted look something like this "chart_param_values"=>{"value"=>"", "chart_param_id"=>"10024"}".
chart_type.rb
attr_accessible :multiple_indicators, :name, :chart_params_attributes
has_many :chart_params, :dependent => :destroy
accepts_nested_attributes_for :chart_params, :allow_destroy => true
def self.single_indicator
where(:multiple_indicators => false)
end
def self.multiple_indicators
where(:multiple_indicators => true)
end
chart_param.rb
attr_accessible :chart_type_id, :name, :required, :tooltip
belongs_to :chart_type
chart_param_value.rb
attr_accessible :chart_param_id, :indicator_id, :main_indicator_chart_id, :value
belongs_to :chart_param
#belongs_to :chart_type
belongs_to :indicator
indicator.rb
attr_accessible :chart_type_id, :description, :help_text, :key_name, :name, :display_screen, :any_details, :indicator_details_attributes, :chart_param_values_attributes
belongs_to :chart_type
has_many :chart_param_values, :dependent => :destroy
accepts_nested_attributes_for :chart_param_values
indicators/_form.html.erb
<%= form_for(#indicator) do |f| %>
...
<div class="field">
<%= f.label "Chart Type" %>
<%= f.select :chart_type_id, ChartType.single_indicator.collect { | ct | [ct.name, ct.id] }, {}, :onchange => "update_chart_params(this);" %>
</div>
<div id="Charts">
<% ChartType.single_indicator.each do |ct| %>
<div id="chart_type_params_<%= ct.id %>" <% if !#indicator.chart_type_id.eql?(ct.id) %> style="display: none" <% end %> >
<% ct.chart_params.each do |ctp| %>
<%= fields_for :chart_param_values do | builder | %>
<%= builder.hidden_field :chart_param_id, :value => ctp.id %>
<%= builder.label :value, ctp.required ? "* #{ctp.name}" : ctp.name %>
<%= builder.text_field :value %><br />
<% end %>
<% end %>
</div>
<% end %>
</div>
<script language="javascript">
update_chart_params = function(select){
alert(select.value);
<% ChartType.single_indicator.each do |ct| %>
$('#chart_type_params_' + <%= ct.id %>).hide();
<% end %>
$('#chart_type_params_' + select.value).show();
}
*Also, if I change the fields_for to f.fields_for and add #indicator.chart_param_values.build to the indicators_controller new/create methods, I get duplicated fields on the form based on how many chart_param_value records were built.
Related
I'm trying to add a validation of 'size' property for 'Creative' model. 'Creative' model is one-to-one related to the 'Ad', and it's field are displayed as a nested form in the 'Ads' form(code provided below).
The problem is, that when I'm actually saving the form, size is not validated — neither with format validator, nor with :presence validator(if I add one). At the same time, :filter property is validated.
Size is a non-model property, added with attr_acessor method and custom setters and getters.
Looking for a way to fix this code or any different solution to add a validation for non-model nested property will be much appreciated.
Controllers:
class Creative < ActiveRecord::Base
attr_accessible :size, :filter
belongs_to :ad
attr_accessor :size
validates :size, :format => { :with => /^\d+x\d+$/, :message => "Incorrect size param. Should be [width]x[height], e.g. 320x50" }
validates :filters, :presence => true
def size
"#{self.width}x#{self.height}"
end
def size=(size)
#width, #height = size.split("x").map(&:to_i)
end
end
class Ad < ActiveRecord::Base
attr_accessible :creative_attributes
has_one :creative
accepts_nested_attributes_for :creative
validates_associated :creative
end
class Campaign < ActiveRecord::Base
has_many :ads
end
Form:
<%= simple_form_for [:rtb, #campaign, #ad], :html => { :class => 'form-horizontal' } do |f| %>
<% if #ad.errors.any? %>
<div id="error_explanation" class="alert alert-error">
<h2><%= pluralize(#ad.errors.count, "error") %> prohibited this ad from being saved:</h2>
<ul>
<% #ad.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :name %>
<%= f.simple_fields_for :creative do |creative_f| %>
<fieldset>
<legend>Creative Settings</legend>
<%= creative_f.input :size %>
<%= creative_f.input :filters %>
</fieldset>
<% end %>
<%= f.button :submit, :class => 'btn-primary' %>
<% end %>
I have three models, and i am trying to save onto a third table using simple form gem and checkboxes.
class Work < ActiveRecord::Base
has_many :skills, through: :skillships
end
The second model is
class Skill < ActiveRecord::Base
has_many :works, through: :skillships
end
The third is
class Skillship < ActiveRecord::Base
belongs_to :work
belongs_to :skill
end
Using the Work model i am trying to save the data on the skillship table. Something similar to this http://railscasts.com/episodes/17-habtm-checkboxes-revised. Can you please help.
EDIT
The form
<%= simple_form_for(#work) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :title, :label => 'Project Title' %>
<%= f.input :excerpt, :as => :text %>
<fieldset>
<legend>Skills Used </legend>
Would like to check the skills i used here.
</fieldset>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
I tried..
<%= hidden_field_tag "work[skill_ids][]", nil %>
<% Skill.all.each do |skill| %>
<%= check_box_tag "work[skill_ids][]", skill.id, #work.skill_ids.include?(skill.id), id: dom_id(skill) %>
<%= label_tag dom_id(skill), skill.title %><br>
<% end %>
The reason i'm doing this it because work can have many skills used.
I was going about this the wrong way. A join table solved the problem.
rails g migration create_skills_works_table
Then
class CreateSkillsWorksTable < ActiveRecord::Migration
def self.up
create_table :skills_works, :id => false do |t|
t.references :skill
t.references :work
end
add_index :skills_works, [:skill_id, :work_id]
add_index :skills_works, [:work_id, :skill_id]
end
def self.down
drop_table :skills_works
end
end
Using simple form on the work view.
<fieldset>
<legend>Skills Used </legend>
<%= f.association :skills %>
</fieldset>
I have problem in getting below code to work.
class Page < ActiveRecord::Base
has_many :page_parts, :through => :page_parts_pages
has_many :page_parts_pages
accepts_nested_attributes_for :page_parts, :allow_destroy => true
accepts_nested_attributes_for :page_parts_pages, :allow_destroy => true
end
class PagePart < ActiveRecord::Base
has_many :page_parts_pages
has_many :pages, :through => :page_parts_pages
end
class PagePartsPage < ActiveRecord::Base
belongs_to :page
belongs_to :page_part
end
Table Structure:-
pages
id, title
pages_parts
id, title
page_parts_pages
id, page_id, page_part_id
View code
<% page_fragment.each do |k,v| %>
<% if v.nil? or v.blank? or v.empty? %>
<% parts = f.object.page_parts.build if f.object.page_parts.blank? %>
<%= f.fields_for :page_parts, parts do |p| %>
<%= render 'page_part_form_field', :f => p %>
<% end %>
<% else %>
<% parts_page = f.object.page_parts_pages.build if f.object.page_parts_pages.blank? %>
<%= f.fields_for :page_parts_pages, parts_page do |p| %>
<%= render 'page_part_page_form_field', :f => p %>
<% end %>
<% end %>
<% end %>
Actually the scenario is, I have to display the fields for page_parts and page_parts_pages on condition basis. If condition is satisfied, display fields for page_parts else display fields for page_parts_pages.
It's working perfectly fine for new action but for edit action it is not displaying correctly.
Any help is highly appreciated.
Thanks in advance
You are creating new page_parts in this form:
parts = f.object.page_parts.build if f.object.page_parts.blank?
parts_page = f.object.page_parts_pages.build if f.object.page_parts_pages.blank?
'build' creates new objects (it will not persist them in database though). So, no wonder it works for new, but not for edit.
You can try this:
<% page_fragment.each do |k,v| %>
<% if v.blank? %>
<%= f.fields_for :page_parts do |p| %>
<%= render 'page_part_form_field', :f => p %>
<% end %>
<% else %>
<%= f.fields_for :page_parts_pages do |p| %>
<%= render 'page_part_page_form_field', :f => p %>
<% end %>
<% end %>
<% end %>
rails api has pretty good documentation of forms_for and other form helpers.
I've been trying recently to show a list of the fields modified with success on submitting a form. The only problem is that my form (I use simple form) doesn't show the errors when there are some and the form can't be submitted.
Here's my code simplified :
def update
#wizard.assign_attributes(params[:wizard])
# Get changed attributes
if #wizard.save
# Set the success flash with fields modified
redirect_to #wizard
else
#title = "Edition du profil"
render 'edit'
end
end
The view :
<%= simple_form_for #wizard do |f| %>
<%= f.input :email %>
<%= f.input :story %>
<%= f.submit "Modifier", :class => "btn success small" %>
<% end %>
The model :
class Wizard < ActiveRecord::Base
has_secure_password
attr_accessible :email, :story, :password, :password_confirmation, :password_digest
serialize :ranks, Array
validates_presence_of :email, :first_name, :last_name, :gender, :story
validates_presence_of :password, :password_confirmation, :unless => Proc.new { |w| w.password_digest.present? }
# Other validations here
has_one :subject, :foreign_key => "teacher_id"
ROLES = %w[teacher]
scope :with_role, lambda { |role| {:conditions => "roles_bitmask & #{2**ROLES.index(role.to_s)} > 0"} }
# Other functions here
end
Has anyone an idea ?
Thank you in advance !
It has probably something to do with how you overwrote AR. I remember some plugin getting in trouble with assign_attributes. Meanwhile you can try :
#wizard.assign_attributes(params[:wizard], :without_protection => true)
If that works it will at least narrow down the problem to mass assignment.
you perhaps missing this part in edit/new view.Where #wizard is your model_name.
Write this piece of code in the form tag.
<% if #wizard.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#wizard.errors.count, "error") %> prohibited this task from being saved:</h2>
<ul>
<% #wizard.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
It's my first time here, and first time I use nested_form gem. Everything seemed to be ok, but the data from my "parent" model doesn't save.
Here is my code
<%= nested_form_for #project do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :tasks %>
<p><%= f.link_to_add "Add a task", :tasks %></p>
<%= f.submit %>
<% end %>
so, when I "submit", just the tasks are saved ok, but not the project name.
Any clue for me? did I miss something??
You need to add the attribute. eg name to attr_accessible.
# app/models/project.rb
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :destroy
accepts_nested_attributes_for :tasks, :allow_destroy => true
attr_accessible :name,:tasks_attributes ## <-- you need this line
end
Your fields_for declaration isn't quite right
<%= f.fields_for :tasks %>
Should be
<%= f.fields_for :tasks do |task_builder| %>
you are also missing an end for that declaration and a render to render the partial that has the nested fields for the associated object.
So you should end up with something like this
<%= f.fields_for :tasks do |task_builder| %>
<%= render 'task_fields', :f => task_builder %>
<% end %>
<p><%= f.link_to_add "Add a task", :tasks %></p>
That should do the trick. all you need to do now is create a _task_field.html.erb partial and add the task fields to it in the usual way using f.label, f.text_field etc...
p.s.
Your code could not possibly have ever worked. You would have had errors so something is probably missing from your opening post.