I have the following one to many associations. Document has many Sections and Section has many Items.
class Document < ActiveRecord::Base
has_many :document_sections, :dependent => :destroy, :autosave => true
has_many :document_items, :through => :document_sections
end
class DocumentSection < ActiveRecord::Base
belongs_to :document
has_many :document_items, :dependent => :destroy, :autosave => true
end
class DocumentItem < ActiveRecord::Base
belongs_to :document_section
end
And the 'edit' action as follows :-
def edit
#document = Document.find(params[:id])
end
Here is the edit.html.erb
<h1>Edit!</h1>
<% form_for(#document) do |f| %>
<%= f.error_messages %>
<p>
<p> Header Comment <p/><br />
<%= f.text_field :comment %>
<%= f.hidden_field :uid %>
</p>
<% #document.document_sections.each do |section| %>
<% f.fields_for :section, :index => section.id do |s| %>
<p>
<%= s.hidden_field :seqnum, options = {:value => section.seqnum} %>
</p>
<% section.document_items.each do |item| %>
<% s.fields_for :item, :index => item.id do |i| %>
<p>
<%= i.text_area :comments, options = {:value => item.comments} %>
</p>
<% end %>
<% end %>
<% end %>
<% end %>
<p>
<%= f.submit "Submit Comments" %>
</p>
<% end %>
I have to specify the options hash with the value attribute set, for eg:
options = {:value => item.comments}
in order to show the item comments when I click the 'edit' link to modify the item comments. Shouldn't they be loaded by default, which seems to be the case for header comments.
Thanks for replying. Yes, i want to render the text area with the item.comments value from the database. The below code I had, does not load the comments.
<% s.fields_for :item, :index => item.id do |i| %>
<p>
<%= i.text_area :comments %>
</p>
<% end %>
can you explain me why
<%= text_area(:item, :comments) %>
works but
<%= i.text_area :comments %>
does not. Thanks much.
It seems your understanding of options is not correct. Here is what it is:
Additional options on the input tag can be passed as a hash with options
Which means that options sets attributes for the HTML tag.
You did not specify what exactly you want to do in the question, but I assume you want to render textarea tag with item.comments as a value. If so then you can use the 2nd parameter method (see the docs) and try this:
text_area(:item, :comments, :size => "20x30")
# => <textarea cols="20" rows="30" id="item_comments" name="item[comments]">
# #{#item.comments}
# </textarea>
Related
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 am trying to edit a Topic which has many Posts.
Edit page for a Topic has Topic's name and Post's content that can be edited.
The mass-assignment error occurs in topics_controller.rb, update method, post.update_attributes(params[:post]).
How do I avoid mass-assignment error.
topic.rb
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
belongs_to :forum
accepts_nested_attributes_for :posts, :allow_destroy => true
attr_accessible :name, :last_post_id, :posts_attributes
end
post.rb
class Post < ActiveRecord::Base
belongs_to :topic
attr_accessible :content
end
topics_controller.rb
def update
#topic = Topic.find(params[:id])
post = #topic.posts.first
if #topic.update_attributes(params[:topic]) && post.update_attributes(params[:post])
topic = Topic.find(#post.topic_id)
flash[:success] = "Success!"
redirect_to topic_posts_path(topic)
else
render 'edit'
end
end
views/topics/edit.html.erb
<%= form_for #topic do |f| %>
<!-- render 'shared/error_messages_topic' -->
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for #topic.posts.first do |post| %>
<%= render :partial => "posts/form", :locals => {:f => post} %>
<% end %>
<%= f.submit "Edit", class: "btn btn-large btn-primary" %>
<% end %>
views/posts/_form.html.erb
<%= f.label :content %>
<%= f.text_area :content %>
In update method you don't have to update attributes of both the models instead of if #topic.update_attributes(params[:topic]) && post.update_attributes(params[:post]) it should this only if #topic.update_attributes(params[:topic]) it will update the posts automatically.
And change your view from this <%= f.fields_for #topic.posts.first do |post| %> to <%= f.fields_for :posts, #topic.posts.first do |post| %> it will work fine.
For more information read this http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
I am trying to create a nested form to handle a has_many :through relationship and getting duplicated fields being rendered.
Models
Company
has_many :provides
has_many :services, :through => :provides
accepts_nested_attributes_for :services, :provides
attr_accessible :service_ids
Provide
belongs_to :company
belongs_to :service
Service
has_many :provides
has_many :companies, :through => :provides
has_many :portfolio_items
acts_as_nested_set
Controller
Settings/Services
def index
#company_services = #company.services
#service_list = Service.where("parent_id IS NULL")
end
def show
#user = current_user
# Find features for supplier based users
unless #company.blank?
#my_sectors = #company.sectors
end
end
def update
if params[:company].nil?
#company.service_ids = nil
end
respond_to do |format|
if #company.update_attributes(params[:company])
format.html { redirect_to settings_path, :notice => "Services successfully updated" }
else
format.html { render :index }
end
end
end
Views
Form -
<%= form_for #company, :url => settings_service_path(#company), :method => :put do |f| %>
<div>
<ul>
<% #service_list.each do |item| %>
<%= f.fields_for :provides do |p| %>
<%= p.fields_for :services do |s| %>
<%= render :partial => "subs", :locals => {:subs => s, :service => item, :f => f, :p => p } %>
<% end %>
<% end %>
<% end %>
</ul>
<%= submit_tag("Update") %>
<% end %>
_subs.html.erb
<li>
<%= check_box_tag :service_ids, service.id, #company.services.include?(service), :name => "company[service_ids][]", :class => "checkbox" %>
<%= label_tag service.id, service.service_name %>
<% unless service.children.blank? %>
<ul>
<%= render :partial => "subs", :collection => service.children %>
</ul>
<% end %>
</li>
I know the fields_for is causing the duplication but I don't know why?
Could anybody clarify?
You need to write,
<% #service_list.each do |item| %>
<%= f.fields_for :provides do |p| %>
<%= p.fields_for :services, item do |s| %>
this way fields_for will iterate only for matching service each time.
I have a model:
class Contact < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
I want to build 50 phone #s that users can add (there may already be phones 1 or 5, but I always want 50 available)
In my controller:
while contact.phones.length < 50
contact.phones.build({:phone_type_id => PhoneType['a_cool_type'].id})
end
In my view, I want to have 2 columns of phone #s 25 rows each
<%= semantic_form_for contact do |form| %>
<table width=50%>
<%= form.inputs :for => :phones[0..25] do |phone_form| %>
<td align="center"><%= phone_form.input :number, :label => false %></td>
....
<% end %>
</table>
<table width=50%>
<%= form.inputs :for => :phones[25..49] do |phone_form| %>
<td align="center"><%= phone_form.input :number, :label => false %></td>
....
<% end %>
</table>
<%end %>
Obviously the line:
<%= form.inputs :for => :phones[25..49] do |phone_form| %>
doesn't work, but it conveys my intention ( I hope). I want to have more control over how formtastic grabs the underlying object association.
The following works, but I can't do two columns easily without fancy css.
<%= form.inputs :for => :phones do |phone_form| %>
Any suggestions?
---------- Update ----
I was able to get around this in a roundabout way:
I built up a separate list of phone #s not as contact.phones.build, but Phone.new(:contact_id => contact.id) and store those in a list called #new_phones
Then my form looks like this:
<%= semantic_form_for #contact, :url => ..., do |f| %>
<% #new_phones[0...25].each_with_index do |phone, i| %>
<%= f.fields_for :phones, phone, :child_index => i do |phone_form| %>
<%= render "phone_fields", {:phone_form => phone_form, :phone => phone} %>
<%end%>
<% end %>
....
<% #new_phones[25...50].each_with_index do |phone, i| %>
<%= f.fields_for :phones, phone, :child_index => i+25 do |phone_form| %>
<%= render "phone_fields", {:phone_form => phone_form, :phone => phone} %>
<%end%>
<% end %>
<%end%>
This allowed me to display 25 phones on one part of the page, and 25 on another, with nested_attributes_for :phones working as expected on form submit.
I've always had problems with getting nested attributes working as I want but this may help resolve your issue.
Model:
class Contact < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
Controller:
See we're looping #contract.phones.build 50 times, this creates 50 new instances.
class Contact < ApplicationController
def new
#contact = Contact.new
25.times do
#contact.phones.build
end
end
end
View new.html.erb :
...
<%= p.semantic_fields_for :phones do |ec| %>
<%= ec.input :number %>
<% end %>
...
I did try a few attempts to intercept the loop, sadly with no definite clean avail.
I have 2 models:
Video:
class Video < ActiveRecord::Base
belongs_to :user
has_many :thumbnails
attr_accessor :search, :saveable
accepts_nested_attributes_for :thumbnails, :allow_destroy => true
en
d
Thumbnail:
class Thumbnail < ActiveRecord::Base
belongs_to :video
end
I am using the YouTubeG gem in order to search for videos.
Each video that is returned by the search has a form in the view:
<% form_for :video, :url => videos_path, :html => { :class => :form } do |f| -%>
<%= f.hidden_field :url, :value => video.unique_id %>
<%= f.hidden_field :name, :value => video.title %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<% if video.thumbnails.present? %>
<% f.fields_for :thumbnails, video do |t| %>
<% video.thumbnails.each do |thumbnail| -%>
<%=image_tag thumbnail.url %>
<%=t.text_field :url, :value => thumbnail.url %>
<% end -%>
<% end -%>
<% end %>
<%= f.submit "Save" %>
<% end -%>
The f.fields_for :thumbnails produces
<input type="hidden" value="http://i.ytimg.com/vi/s8eigkwmMEo/0.jpg" name="video[thumbnails][url]" id="video_thumbnails_url"/>
which seems to wrong because I want to save all thumbnails for this video.
When I try to save I get
ActiveRecord::AssociationTypeMismatch in VideosController#create
Parameters:
{"commit"=>"Save",
"video"=>{"name"=>"Karajan - Beethoven Symphony No. 7",
"url"=>"s8eigkwmMEo",
"user_id"=>"1",
"thumbnails"=>{"url"=>"http://i.ytimg.com/vi/s8eigkwmMEo/0.jpg"}}} < there should be 4 thumbnails
I found the correct answer:
<% f.fields_for "thumbnails_attributes[]", Thumbnail.new do |t| %>
instead of
<% f.fields_for :thumbnails, video do |t| %>
You should use index feature of the fields_for helper:
<% video.thumbnails.each do |thumbnail| -%>
<% f.fields_for "thumbnail[]", thumbnail do |t| %>
<%=image_tag thumbnail.url %>
<%=t.text_field :url, :value => thumbnail.url %>
<% end -%>
<% end -%>
Look through rails casts edipode trilogy about complex forms:
Episode 1