Controller: project_sub_types_controller.rb
def new
#svn_repos = ['svn_software','svn_hardware']
#project_sub_type = ProjectSubType.new
#project_sub_type.repositories.build
end
Model: project_sub_type.rb
class ProjectSubType < ActiveRecord::Base
belongs_to :project_type
has_many :repositories, :dependent => :destroy
accepts_nested_attributes_for :repositories
def repositories_attributes=(attributes)
# Process the attributes hash
end
end
View: _form.html.erb
<%= form_for #project_sub_type, :html => {:class => 'project_subtype_form'} do |f| %>
<%= f.label :name, "Project sub type name" %>
<%= f.text_field :name %>
<%= f.fields_for :repositories do |ff| %>
<%= ff.label :select_svn_repositories, "Select SVN repositories" %>
<% #svn_repos.each do |repos| %>
<%= ff.check_box :repos_name, {}, "#{repos}", nil %>
<%= h repos -%>
<% end %>
<%= f.submit "Save"%>
fields_form inspect element :
<input id="project_sub_type_repositories_attributes_0_repos_name" type="checkbox" value="svn_software" name="project_sub_type[repositories_attributes][0][repos_name]">
svn_software
<input id="project_sub_type_repositories_attributes_0_repos_name" type="checkbox" value="svn_hardware" name="project_sub_type[repositories_attributes][0][repos_name]">
svn_hardware
After submitting the form the params = "repositories_attributes"=>{"0"=>{"repos_name"=>"svn_hardware"}}} even after checking both the checkboxes it is using the last selected check_box that is 'svn_hardware'
[EDIT]
Desired Output : My final output should be what the user selects so in this case it should be like this in my after submit params = "repositories_attributes"=>{"0"=>{"repos_name"=>"svn_software"}{"1"=>{"repos_name"=>"svn_hardware"}}
I believe the reason that both have 0 as a prefix is that you have solely specified one repository object, while your array (#svn_repos) contains two items. Because you only build one new object (through #project_sub_type.repositories.build), you create two checkboxes for the same model.
If you, however, were to instead do this:
# controller (inside new method)
#project_sub_type.repositories.build # 1 new object
#project_sub_type.repositories.build # 2 new objects
And then you'd have to iterate over both these objects in your _form partial, and map the names up to the #svn_repos array. I would much prefer this solution though:
# controller (inside new method)
#project_sub_type.repositories.build name: 'svn_software'
#project_sub_type.repositories.build name: 'svn_hardware'
And then iterate over the repositories in the partial, using the name attribute of the model rather than that of an array.
As Nicolay explains, the reason you have a 0 is because you build this #project_sub_type.repositories.build object once. Everything in your code is correct. But if you have to select multiple checkboxes then according to the DOCS
In View: _form.html.erb change
<%= ff.check_box :repos_name, {}, "#{repos}", nil %>
TO
<%= ff.check_box :repos_name, {:multiple => true}, "#{repos}", nil %>
Now you should be able to see the params after submit as below:
=>{"0"=>{"repos_name"=>["svn_software", "svn_hardware"]}}
Related
I got simple_form for testrun model with multiple checkboxes, that save an array of testcases in a model field
app/views/testruns/_form.html.erb
<%= simple_form_for #testrun do |f| %>
<%= f.input :testcase, as: :check_boxes,
collection: [["testcase1", :testcase1], ["testcase2", :testcase2], ... ]%>
<%= f.submit %>
<% end %>
It works fine, but from now I need to create another model called testcase. After submitting form, besides creating a new testrun instance, I need to create testcase instances which depends on every flag checked.
Any idea how can I do it?
You need to use accepts_nested_attributes_for and simple_fields_for. Assuming you have has_many :testcases in Testrun and the field name of Testcase is name, the below steps should put you in the right direction.
#app/models/testrun.rb
accepts_nested_attributes_for :testcases
#app/controllers/testrun_controller.rb
def new
#testrun = Testrun.new
#testrun.testcases.build
end
private
def testrun_params
params.require(:testrun).permit(:field1, :field2.., testcases_attrubtes: [name: []])
end
#app/views/testruns/_form.html.erb
<%= simple_form_for #testrun do |f| %>
<%= f.simple_fields_for :testcases do |testcase| %>
<%= testcase.input :name, as: :check_boxes,
collection: [["testcase1", :testcase1], ["testcase2", :testcase2], ... ]%>
<% end %>
<%= f.submit %>
<% end %>
In my rails application the following relationships exist:
user belongs_to :team ,
element belongs_to :team ,
task belongs_to :element
A user can then create a task which belongs to an element.
When a user is creating a task, they can select the element they would like the task to belong to. How do I show only the elements that belong to the current_user's team? I am using Devise to get the current_user.
The samples below do not work.
<div class="field">
<%= form.label :element_id %>
<%= form.select :element_id, options_for_select(Element.current_user.team_id.map{|s|[s.title, s.id]}),{ :multiple => true} %>
</div>
I also tried to call the method below from the tasks_controller.rb file but it didnt work either
def new
#task = Task.new
#tasks_element_dropdown = Element.current_user.team_id.map{|s|[s.title, s.id]}
end
In the tasks/_form.html.erb file, I called the method with the code below
<%= form.select :element_id, options_for_select(#tasks_element_dropdown),{ :multiple => true} %>
When I tried the example below it does work but it displays all elements, and I only want the elements that belong to the user's team to display
<div class="field">
<%= form.label :element_id %>
<%= form.select :element_id, options_for_select(Element.all.map{|s|[s.title, s.id]}),{ :multiple => true} %>
</div>
The problem is in the following code, which should return the elements:
Element.current_user.team_id.map{|s|[s.title, s.id]}
Since you have a user, you can get the team: current_user.team
And then get the elements of the team (as long as has_many :elements is defined in the Team class): current_user.team.elements
Thus, the final code should be something like:
<div class="field">
<%= form.label :element_id %>
<%= form.select :element_id, options_for_select(current_user.team.elements.map{ |s| [s.title, s.id] }),{ :multiple => true} %>
</div>
I want to create a task and assign to a particular user who has_one profile with first name and last name.
And also user has_many tasks.
My new task form is
<%= form_for :task do |f| %>
<div>
<%= f.label :task %>
<%= f.text_area :task %>
</div>
<div>
<%= f.label :assigned_to %>
<%= f.collection_select(:assigned_to, User.profile.all, :fist_name, :fist_name, :include_blank => 'None')%>
</div>
in the collection select I should display something like " Sam Parker (sam#org.com)" like this all the users should be available in the collection select field.
Can anyone help me how to display it.
First of all read the documentation here:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-collection_select
I guess you need to create a method that returns the option's text, for example:
class User < ActiveRecordBase
# ...
def label_for_select
"#{profile.full_name} (#{profile.email})"
end
end
Then, in your view it would be something like:
<div>
<%= f.label :assigned_to_id %>
<%= f.collection_select(:assigned_to_id, User.all, :id, :label_for_select, :include_blank => 'None')%>
</div>
Notice that the form sets the assigned_to_id not the assign_to ruby object. Rails will instantiate the assign_to object based on this id.
I have a parent which has multiple children. I want it so that when I submit my form, a parent is generated in the parent model, and multiple records are created in the child model, one for each child. When I try and submit, I get the following error:
ActiveRecord::AssociationTypeMismatch in ParentsController#create
Child(#) expected, got Array(#)
When I uncomment accepts_nested_attributes_for :children and change f.fields_for :children to f.fields_for :children_attributes, I get a different error:
TypeError in ParentsController#create
can't convert Symbol into Integer
I am at a loss as to what to do. I have checked out the nested model forms railscasts, but they were dealing with generating children fields inside the form, and what I learned from the railscasts didn't seem to work. I am pretty I am doing my builder.text_field :cname's in my form wrong, but I'm not aware of the proper way to do it.
My code:
parent.rb
class Parent < ActiveRecord::Base
has_many :children
#accepts_nested_attributes_for :children
attr_protected :id
child.rb
class Child < ActiveRecord::Base
belongs_to :parent
attr_protected :id
_form.html.erb
<%= form_for #parent, :url => { :action => "create" } do |f| %>
<%= f.text_field :pname %>
<%= f.fields_for :children do |builder| %>
<%= builder.text_field :cname %>
<%= builder.text_field :cname %>
<%= builder.text_field :cname %>
<% end %>
<%= f.submit %>
<% end %>
params content:
{"utf8"=>"✓",
"authenticity_token"=>"FQQ1KdNnxLXolfes9IGiO+aKHJaPCH+2ltDdA0TwF7w=",
"parent"=>{"pname"=>"Heman",
"child"=>{"cname"=>""}},
"commit"=>"Create"}
The problem here is that the generated form in HTML for the children are using the same "place" (same pair key/value) in the params Hash (using the params[:parent][:child][:cname] pair). This is why there is only one param 'name' in the 'child' node in the Params hash.
To avoid that, you can use an array for the input's name:
<input type="text" name="child[][cname]" />
<input type="text" name="child[][cname]" />
The params, when this submitted, will look like this:
params: {
child: [ { cname: 'blabla' }, { cname: 'bonjour' } ]
}
To get the desired result, in your case:
<%= form_for #parent, :url => { :action => "create" } do |f| %>
<%= f.text_field :pname %>
<%= text_field_tag "parent[children][][cname]" %>
<%= text_field_tag "parent[children][][cname]" %>
<%= text_field_tag "parent[children][][cname]" %>
<%= f.submit %>
<% end %>
Should produce something like this:
{
"utf8"=>"✓",
"authenticity_token"=>"FQQ1KdNnxLXolfes9IGiO+aKHJaPCH+2ltDdA0TwF7w=",
"parent"=> {
"pname"=>"Heman",
"children"=> [
{ "cname"=>"SisiSenior" },
{ "cname"=>"Bonjor" },
{ "cname"=>"Blabla" }
]
},
"commit"=>"Create"}
So in your controller, you could use something like this:
#ParentsController
def create
children_attributes = params[:parent].delete(:children) # takes off the attributes of the children
#parent = Parent.create(params[:parent])
children_attributes.each do |child_attributes|
child = #parent.children.create(child_attributes)
end
end
On the front page of my rap lyrics explanation site, there's a place where users can try explaining a challenging line:
alt text http://dl.dropbox.com/u/2792776/screenshots/2010-02-06_1620.png
Here's the partial I use to generate this:
<div class="stand_alone annotation" data-id="<%= annotation.id %>">
<%= song_link(annotation.song, :class => :title) %>
<span class="needs_exegesis"><%= annotation.referent.strip.gsub(/\n/, "\n <br />") %></span>
<% form_for Feedback.new(:annotation_id => annotation.id, :created_by_id => current_user.try(:id), :email_address => current_user.try(:email)), :url => feedback_index_path, :live_validations => true do |f| %>
<%= f.hidden_field :annotation_id %>
<%= f.hidden_field :created_by_id %>
<p style="margin-top: 1em">
<%= f.text_area :body, :rows => 4, :style => 'width:96%', :example_text => "Enter your explanation" %>
</p>
<p>
<% if current_user %>
<%= f.hidden_field :email_address %>
<% else %>
<%= f.text_field :email_address, :example_text => "Your email address" %>
<% end %>
<%= f.submit "Submit", :class => :button, :style => 'margin-left: .1em;' %>
</p>
<% end %>
</div>
However, putting more than one of these on a single page is problematic because Rails automatically gives each form an ID of new_feedback, and each field an ID like feedback_body (leading to name collisions)
Obviously I could add something like :id => '' to the form and all its fields, but this seems a tad repetitive. What's the best way to do this?
If you don't want to change your input names or your model structure, you can use the id option to make your form ID unique and the namespace option to make your input IDs unique:
<%= form_for Feedback.new(...),
id: "annotation_#{annotation.id}_feedback"
namespace: "annotation_#{annotation.id}" do |f| %>
That way our form ID is unique, i.e. annotation_2_feedback and this will also add a prefix, e.g. annotation_2_, to every input created through f.
Did you consider nested_attributes for rails models? Instead of having multiple new feedback forms where each is tied to an annotation, you could have multiple edit annotation forms where each annotation includes fields for a new feedback. The id's of the generated forms would include the annotations id such as edit_annotation_16.
The annotation model would have a relationship to its feedbacks and will also accept nested attributes for them.
class Annotation < ActiveRecord::Base
has_many :feedbacks
accepts_nested_attributes_for :feedbacks
end
class Feedback < ActiveRecord::Base
belongs_to :annotation
end
You could then add as many forms as you want, one for each annotation. For example, this is what I tried:
<% form_for #a do |form| %>
Lyrics: <br />
<%= form.text_field :lyrics %><br />
<% form.fields_for :feedbacks do |feedback| %>
Feedback: <br/>
<%= feedback.text_field :response %><br />
<% end %>
<%= form.submit "Submit" %>
<% end %>
<% form_for #b do |form| %>
Lyrics: <br />
<%= form.text_field :lyrics %><br />
<% form.fields_for :feedbacks do |feedback| %>
Feedback: <br/>
<%= feedback.text_field :response %><br />
<% end %>
<%= form.submit "Submit" %>
<% end %>
And the quick and dirty controller for the above edit view:
class AnnotationsController < ApplicationController
def edit
#a = Annotation.find(1)
#a.feedbacks.build
#b = Annotation.find(2)
#b.feedbacks.build
end
def update
#annotation = Annotation.find(params[:id])
#annotation.update_attributes(params[:annotation])
#annotation.save!
render :index
end
end
I had this same issue on a site I'm currently working on and went with the solution you mention at the bottom. It's not repetitive if you generate the ID programmatically and put the whole form in a partial. For example, on my site, I have multiple "entries" per page, each of which has two voting forms, one to vote up and one to vote down. The record ID for each entry is appended to the DOM ID of its vote forms to make it unique, like so (just shows the vote up button, the vote down button is similar):
<% form_for [entry, Vote.new], :html => { :id => 'new_up_vote_' + entry.id.to_s } do |f| -%>
<%= f.hidden_field :up_vote, :value => 1, :id => 'vote_up_vote_' + entry.id.to_s %>
<%= image_submit_tag('/images/icon_vote_up.png', :id => 'vote_up_vote_submit' + entry.id.to_s, :class => 'vote-button vote-up-button') %>
<% end -%>
I also had the same issue but wanted a more extensible solution than adding the ID to each field. Since we're already using the form_for ... |f| notation the trick is to change the name of the model and you get a new HTML ID prefix.
Using a variant of this method: http://www.dzone.com/snippets/create-classes-runtime (I removed the &block stuff)
I create a new model that is an exact copy of the model I want a second form for on the same page. Then use that new model to render the new form.
If the first form is using
#address = Address.new
then
create_class('AddressNew', Address)
#address_new = AddressNew.new
Your ID prefix will be 'address_new_' instead of 'address_' for the second form of the same model. When you read the form params you can create an Address model to put the values into.
For those stumbling here, looking for the solution for Rails 3.2 app, look at this question instead:
Rails: Using form_for multiple times (DOM ids)