I have a model Responsibility with has one text field of responsibility. Other model is Stage, in Stage form field there is a text_field responsibility I want to render an option list from responsibilities table how can i do that in rails?
routes.rb
resources :projects do
resources :responsibilities
resources :stages
end
stage _form.html.erb
<%= form_with(model: stage, url: [#project, stage], local: true) do |form| %>
<div>
<%= form.label :responsibility, :class=>"required" %>
<%= form.text_field :responsibility %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
How can I render responsibilities list as an option in stage responsibility form field?
what is tried is:
stage _form.html.erb
<div>
<%= form.label :responsibility %>
<%= select_tag "colors", #responsibilities , multiple: true %>
</div>
stages_controller.rb
def new
#stage = Stage.new
#project = Project.find(params[:project_id])
#responsibilities = #project.responsibilities
end
I was able to render form but in responsibility field none of the responsibility was accessed as option.
select_tag accepts as a second parameter string that contains options as a string.
Rails provides some helper methods that are useful for generation of those <option>
tags
options_from_collection_for_select, options_for_select
If you inspect with your browser's developer tools the html code of the <select> tag you will see something like this:
<select name="colors[]" id="colors" multiple="multiple">
#<Responsibility::ActiveRecord_Relation:0x00007f3f72cc7eb0>
</select>
This is because select_tag calls to_s method of #responsibilities collection.
The correct way of creating select_tag would looks something like this:
<%= select_tag "colors", options_from_collection_for_select(#responsibilities, :id, :name) , multiple: true %>
There is another way to build select field using the FormBuilder method collection_select. It might look something like this:
<div>
<%= form.label :responsibility %>
<%= form.collection_select :responsibility, #responsibilities, :id, :name, prompt: true %>
</div>
I hope this answer will be useful.
Related
I have a form in my rails app that accepts nested attributes. However, what I want to do is for rails to reject the creation of the nested model if a checkbox (outside the model itself) is checked.
Any idea on how to pass an attribute to the :reject_if option of the accepts_nested_attributes_for in the model from the controller?
Thank you very much in advance.
EDIT:
My controller looks like this:
def new
#course = Course.new
#course.course_template = CourseTemplate.new
end
def create
#course = Course.new(course_params)
#course.user = current_user
if #course.save
flash[:success] = t(".new_course_created_succefully")
redirect_to courses_path
else
render 'new'
end
end
And the form:
<%= form_for #course do |f| %>
<%= render 'shared/error_messages', error_model: #course %>
<div class="form-group has-feedback mb">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group has-feedback mb">
<div class="checkbox c-checkbox needsclick">
<label class="needsclick">
<%= check_box_tag "template", "1", false, {class: "needsclick"} %>
<span class="fa fa-check"></span>Is Template?
</label>
</div>
</div>
<%= f.fields_for :course_template do |ff| %>
<div class="form-group has-feedback mb">
<%= ff.label :name %>
<%= ff.text_field :name %>
</div>
<% end %>
<% end %>
send that checkbox as a parameter from the form and put the build operation inside an if statement. No need to bother with the reject_if
You need to handle your create and build operations separately. so instead of passing your model all attributes, youll pass the model the model attributes, and the association, the nested attributes
# controller
course = Course.new(course_params.reject{|attrib| attrib == :course_template_attributes})
unless params[:skip_create]
course.course_templates.build(course_params[:course_template_attributes]
end
...
what you need to do is conditionally create the course_templates, so you can just pass Course.new all your course_params because that creates both the course and the templates, which needs to be done separately.
Note I'm shorthanding with that reject statement up there. you can either manually add in the various params or better yet create another method with strong params and whitelist only the model attributes (not including the course_template_attributes)
additionally. the params[:skip_create] is whatever the parameter is for that checkbox that decides whether or not you want to create the templates
I have what I hope to be a simple question. I need to display the value for an attribute on the Edit page, while keeping the input field for the same attribute. How might this be accomplished?
Well generally you can just use the original object, like you'll have an #foo that you'll have used in your form_for statement, so you can just use that directly: = #foo.the_attribute
If you're within a partial, or elsewhere where you have only the form builder instance, then you can refer to the underlying object with the .object method, eg.:
= form_for #foo do |f|
# in here, f.object == #foo
In my case, I'm working with accepts_nested_attributes_for in two models. Event accept nested objects from Speaker. And Speaker has a perfil_id attribute which could be ['Maker', 'Developer', 'Entrepreneur', ...].
The Speaker's form is a partial rendered from the principal form, Event's form:
<%= form_for(event) do |f| %>
<%= f.text_field :title %>
<%= f.label :title, 'Event name' %>
<%= f.fields_for :speakers do |builder| %>
<%= render 'events/partials/speaker_fields', f: builder %>
<% end %>
<%= f.submit %>
<% end %>
Partial
<%= builder.number_field :name %>
<%= builder.label :name %>
<% options = options_from_collection_for_select(#profiles, 'id', 'name', f.object.member_profile_id ) %>
<%= select_tag "event[speakers_attributes][profile_id]", options, prompt: 'Select a Profile' %>
When editing Event's Speakers I wanted a select_tag to select the profile name for the actual Speaker.
I could not use an input field for this. So I need to get the correct values from the builder object and I get what I need by doing this:
f.object.profile_id
Passing it as a fourth param to the select options I get this working:
<% options = options_from_collection_for_select(#profiles, 'id', 'name', f.object.profile_id ) %>
I hope it could be useful for you too!
I have a Client model that can have many Projects.
These are my view files:
edit.html.erb
<%= form_for(#project) do |f| %>
<%= render 'fields', :f => f %>
<%= f.submit Create %>
<% end %>
_fields.html.erb
<div>
<%= f.label :name %><br/>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :client_id %><br/>
<%= f.select(:client_id, current_user.client_names) %>
</div>
This is easy and works great.
But is there a way to create a Project from within a Client view as well?
For example on the client edit page it would be nice to have a link New Project for this Client that leads to the above New Project form, but with the respective client preselected in the select box.
Can this be done somehow?
I can't seem to find a way to pass the Client ID to the New Project form.
Thanks for any help!
This is certainly possible, but requires passing the client id to the new_projects_path. This can be done by nesting the routes to projects inside of clients, or just appending the client id. The difference would be URLs that look like the following:
/clients/1/projects/new
- or -
/projects/new?client_id=1
In your projects controller, you should be able to instantiate the #project variable with a preselected client:
#project = Project.new :client_id => params[:client_id]
Yes, you can do this. You're going to use accepts_nested_attributes_for :project in your Client model. Nesting this will allow you to do something like
<%= f.fields_for :project do |p| %>
<fieldset>
<%= p.text_area :content %>
</fieldset>
<% end %>
Check out the railscasts episode #196 on Nested Model Form.
What is the correct way to include a select field within a nested form in Rails 3.2?
I currently have
//IN THE PARENT FORM
<%= f.fields_for :crayons do |crayon| %>
<%= render 'caryon_fields', :f=>crayon %>
<% end %>
//IN THE PARTIAL
<div class="nested-fields">
<%= select (:crayon, :color, [['Red',1],['Blue',2],['Yellow',3],['Green',4]] ) %>
</div>
This is not saving the selected value to the database. I assume this is because the builder is not being passed.
How should I define a select field with hardcoded options in a nested field? Do I need to change tag, i.e. select_tag or collection_select. I'm still unsure of the differences between all these. If anyone can point me towards a clear description it would be much appreciated.
Thanks!
You need associate to your form in your partial like that :
<div class="nested-fields">
<%= f.select (:crayon, :color, [['Red',1],['Blue',2],['Yellow',3],['Green',4]] ) %>
</div>
Whitout partial it's :
<%= f.fields_for :crayons do |crayon| %>
<div class="nested-fields">
<%= crayon.select (:crayon, :color, [['Red',1],['Blue',2],['Yellow',3],['Green',4]] ) %>
</div>
<% 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)