I have not been able to figure out if this is a simple_fields_for problem, a cocoon issue, or something else. If I have blundered with a </div> placement, I don't see it.
When the form first displays, it renders an input field for protocol name. The user can click buttons to add form elements of interest. This works fine and looks like this:
Here's how it looks after the user has clicked on each of the "Add an element" buttons:
The user can add 0..many of each of the elements. When they click on 'Save' it all works really well.
If there is a validation error in one of the fields, the form re-renders fine with one exception. Validation errors for the "Imaging Step" elements do not re-display at all. The other elements re-render and are highlighted as expected when validation fails.
Here's a pictorial example. The user fills out part of the form, having forgotten to select a "Sequence" and having forgotten to enter text for "Tip Description":
After clicking 'save' and failing validation, the form re-renders like this:
As you can see, the Imaging Step section has not been redrawn.
If I look at params in the context of the view, everything seems to be there. #protocol.errors looks right to me as well. Models seem OK too.
Here is a pastebin of the form code.
Here is a pastebin of _step_item_fields.html.erb.
Here is a pastebin of _tip_fields.html.erb.
Here is a pastebin of my Gemfile.
UPDATE:
if I build a step_item like this:
<div id="step_items">
<%= f.simple_fields_for :step_items, #protocol.step_items.build do |si| %>
<%= render 'step_item_fields', :f => si %>
<%end%>
</div>
The Imaging Step section is always drawn, but (obviously) does not populate when validation fails. This also confuses the feature of letting the user add/remove 0..many Imaging Steps.
I also tried:
<div id="step_items">
<%= f.simple_fields_for :step_items, #protocol.step_items.build(protocol_params) do |si| %>
<%= render 'step_item_fields', :f => si %>
<%end%>
</div>
... and other variants when protocol_params is available, but ran in to forbidden params issues.
UPDATE2:
I also tried building a hash with params for a step_item. I can use this here:
<div id="step_items">
<%= f.simple_fields_for :step_items, #protocol.step_items.build(some_ok_params) do |si| %>
<%= render 'step_item_fields', :f => si %>
<%end%>
</div>
... but only for a single step_item. Am not sure how to pass a hash of hashes reflecting the 0..many functionality. Also, building a step_item this way populates the form element correctly, but does not include the error highlighting styling. This is about the time I started wondering why the simpler solution was not working.
Since StepItem is a sub-type of the STI class Step, I think the error detection for StepItems was getting missed. My hack fix here is not pretty and admittedly brittle. Please post a better way if you have one.
I changed this in _form.html.erb:
...
<%if params["protocol"] && params["protocol"]["step_items_attributes"].present?%>
<%params["protocol"]["step_items_attributes"].each do |sia|%>
<%v = sia[1]%>
<div id="step_items">
<%= f.simple_fields_for :step_items, #protocol.step_items.build(:orientation_id => v["orientation_id"], :sequence_id => v["sequence_id"], :note => v["note"], :id => v["id"], :protocol_id => v["protocol_id"], :institution_id => v["institution_id"] ) do |si| %>
<%= render 'step_item_fields', :f => si%>
<% end %>
</div><!-- end step_items-->
<%end%>
<%else%>
...
I changed this in _step_item_fields.html.erb:
...
<div class="nested-fields">
<div class= "form-inputs">
<div class="row">
<div class="col-sm-2 text-right">Imaging Step:</div>
<div class="col-sm-2 drop_col ">
<%= f.collection_select :orientation_id, Orientation.where("institution_id=?",current_user.current_institution_id),:id,:name, {:prompt => "Pick an Orientation", }, {class: "form-control #{"dropdown_error" if f.object.orientation_id.blank? && (f.object.sequence_id.present? || f.object.note.present?)}"}%>
</div>
<div class="col-sm-2 drop_col ">
<%= f.collection_select :sequence_id, Sequence.where("institution_id=?",current_user.current_institution_id),:id,:name, {:prompt => "Pick a Sequence"}, {class: "form-control #{ "dropdown_error" if f.object.sequence_id.blank? && (f.object.orientation_id.present? || f.object.note.present?) }"}%>
</div>
</div>
<div class="row">
<div class="col-sm-2"></div>
<%= f.input :note, :wrapper_html =>{:class => 'col-sm-8'}, label: false, placeholder: 'You can put an optional note here.' , :input_html => {:size => 50}%>
<%= f.input :institution_id,:as => :hidden, :input_html => {:value=>current_user.current_institution_id} %>
<%= f.input :id,:as => :hidden %>
<div class="col-sm-2">
<%= link_to_remove_association "Remove Imaging Step", f , :class=>"btn btn-danger btn-xs placemid",title: "Click here to delete this imaging step.", data: {toggle: "tooltip", placement: "auto", animation: true, delay: {show: 700, hide: 100}}%>
</div>
</div>
</div>
<div class="col-sm-12"><hr></div>
</div>
...
And I added this to the correct stylesheet:
.dropdown_error{
color: red;
}
The form now displays StepItem errors correctly as seen here:
Related
I'm very new to Rails, so please bear with me. I'm currently trying to add a search widget to my homepage (room booking app).
All I need users to do is to select one of the room attributes (home_type) from the drop down menu and then click the button "search" to see the results. So here is what I'm struggling with:
How should I structure the search part on the homepage. With the approach below I'm getting an error of Argument Error in Pages#home. Wrong number of arguments (given 4, expected 1..3).
<%= form_tag search_path, method: :get do %>
<div class="row">
<div class="col-md-6">
<%= select_tag :room, params[:room], [["Apartment", "Apartment"], ["House", "House"]], id: "room", prompt: "Select...", class: "form-control" %>
</div>
<div class="row">
<div class="col-md-offset-4 col-md-4">
<%= submit_tag "Search", class: "btn btn-normal btn-block" %>
</div>
</div>
<% end %>
I'm trying to adapt parts of an airbnb tutorial to my needs, so not sure if I'm doing it right.
Should be something like this
select_tag :room, [["Apartment", "Apartment"], ["House", "House"]], id: "room", prompt: "Select...", class: "form-control"
Note, that to set a value from params you`ll
On the edit page for this form all of the fields outside of the fields_for tag (inbox name, automatic reconciliation, and a few others not listed here) are all populating based on their corresponding db value. However, everything inside the fields_for tag are not, even though they're posting to the db just fine.
I posted :group_member_roles as an example but there are a few other fields inside their own other fields_for that are doing the same thing. It's just confusing that it will post to the db but not display on edit.
The more I read into fields_for the more I feel like I'm not using it correctly. It seems to be more inclined to populating db tables outside of the one your form is currently referencing, but I'm just trying to serialize data within the inbox table. When I look at the :group_member_roles column I want it to be an array/hash containing process true/false, action add/delete, and a string of values.
#_form.html.erb
<%= form_for(#inbox) do |f| %>
<%= f.label :inbox_name %>
<%= f.text_field :name, placeholder: "Inbox Name" %>
<%= f.label :automatic_reconciliation, "Turn on/off automatic reconciliation" %>
<div class="switch small">
<%= f.check_box :automatic_reconciliation, class: "switch-input" %>
<label class="switch-paddle" for="inbox_automatic_reconciliation">
<span class="show-for-sr">Automatic reconciliation</span>
<span class="switch-active" aria-hidden="true">On</span>
<span class="switch-inactive" aria-hidden="true">Off</span>
</label>
</div>
<%= f.fields_for :group_member_roles do |group_member_roles| %>
<h4>Group Member Roles</h4>
<%= group_member_roles.label :process, "Turn On/Off Processing" %>
<div class="switch small">
<%= group_member_roles.check_box :process, class: "switch-input" %>
<label class="switch-paddle" for="inbox_group_member_roles_process">
<span class="show-for-sr">Group Member Roles Processing</span>
<span class="switch-active" aria-hidden="true">On</span>
<span class="switch-inactive" aria-hidden="true">Off</span>
</label>
</div>
<%= group_member_roles.label :action, class: "hide" %>
<%= group_member_roles.select :action, ["Add", "Delete"], { selected: "Add" }, { class: "hide" } %>
<%= group_member_roles.label :values %>
<%= group_member_roles.text_field :values, placeholder: "1234, 1337, 1986" %>
<% end %>
Thanks in advance for any help or guidance.
The fields were being stored as a hash and the field was looking for an object to populate with so I added an OpenStruct dummy object to the fields_for to make it so. If anyone can think of a better way please let me know as this is pretty ugly code.
<%= f.fields_for :group_member_roles, OpenStruct.new(f.object.group_member_roles) do |group_member_roles| %>
I have a nested form where the link_to_add appears only by the side of the last entry, meanwhile the previous entries all have only the link_to_remove.
What I need is for it to be possible to:
1- remove the last entry in the form, currently the link_to_remove does not appear for the last entry.
2- add a new entry between two existing ones, example: if there are 2 entries, 1 and 2, I can only append a new entry after 2, I can't add a new entry between 1 and 2.
This is the code for the partial where one of theses nested forms is generated:
<div id="perguntas">
<%= f.fields_for :perguntas do |m| %>
<div class="field plus-field">
<%= m.input :pergunta , :label=> false , :placeholder => "Escreva uma pergunta" %>
</div>
<%= m.link_to_remove "-",:class => "link-add-field" %>
<% end %>
</div>
<div class="adiciona-botao-field ">
<div class="field plus-field">
</div>
<%= f.link_to_add "+", :perguntas, :class => "link-add-field", 'data-target' => '#perguntas' %>
</div>
I have a checkbox in a view called post_form.html.erb that someone uses to post. Here's the full code of it below:
<%= form_for #post, :html => {:multipart => true} do |f| %>
<%= render 'shared/error_messages', object: #post %>
<div class="field">
<%= f.text_area :content, :cols => 5, :rows => 5 %>
</div>
<div class="ItemContainer">
<div class="ItemInput">Add your photo:<br>
<%= f.file_field :image %>
</div><div class="ItemCheckbox">
<label for="a">Run script?</label>
<div class="ItemCheckboxAlign"><input type="checkbox" id="a"></div>
</div></div><br>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
The above is used to post and I use show.html.erb for the view.
As you can see in the above code, there's a checkbox during the posting process. I want it so that if the checkbox is checked, certain action happens in my show.html.erb view (running a script in this case). If it's not checked, then I don't want to run the script.
Is the best method to store the boolean information on whether the checkbox was checked in the database? My question is, what's the RoR code to make the checkbox associate with the table value?
You're going to want to use jQuery for that:
$('#a').click(function() {
$('#text').toggle();
});
use
$('#check_box_id').is(":checked")
to check if the checkbox is checked or not.
This is a simple question that I'm kinda ashamed to ask, but I've been banging my head against the wall and navigating through the rails 3 documentation without any success :/
So, here is the thing:
When I use the fields_for helper it wraps the generated fields in a <div class="fields"> ... </div> tag.
so, my code is
<ul class="block-grid two-up">
<%= f.fields_for :images do |image_builder| %>
<%= render "images/form", :f => image_builder %>
<% end %>
</ul>
and the generated html is:
<ul class="block-grid two-up">
<div class="fields">
<div>
<label for="company_images_attributes_0_image"> Image</label>
<input id="company_images_attributes_0_image"
name="company[images_attributes][0][image]" type="file">
</div>
</div>
<div class="fields">
<div>
<label for="company_images_attributes_1_image"> Image</label>
<input id="company_images_attributes_1_image"
name="company[images_attributes][1][image]" type="file">
</div>
</div>
</ul>
What I want to do is actually change the <div class="fields"> wrapper tag to <li>.
The documentation says you can pass options to the fields_for, but its not clear about what options you can pass, maybe you can change this wrapper tag?
A possibility could be to override a function, kinda like ActionView::Base.field_error_proc when there is an error in the form.
Quick edit: I forgot to mention that I'm using simple_form to generate this form. I tried looking in the simple_form.rb config file for a way to customize this, but I didn't see any way of doing it.
Solution
After further investigation, it turns out the form was using the nested_form gem as well to generate the form (not only simple_form). This generator was causing the fields_for to be wrapped in the div tag. Thanks everybody for their suggestions!
The following disables the wrapper:
f.fields_for :images, wrapper:false do |image_builder|
then you can add your own wrapper in the builder block.
A cheap solution would be just adding <li> tag into the form like:
<%= f.fields_for :images do |image_builder| %>
<li><%= render "images/form", :f => image_builder %></li>
<% end %>
I am not sure if you can completely eliminate the div tag by passing some params to field_for. But I think you can change the name of div class or id by passing the html block, like in form_for:
<%= form_for #image, :as => :post, :url => post_image_path,
:html => { :class => "new_image", :id => "new_image" } do |f| %>
You said you're using simple_form then you should be saying <%= f.simple_fields_for... Have you tried using wrapper_html option:
<%= f.input :name, :label_html => { :class => 'upcase strong' },
:input_html => { :class => 'medium' }, :wrapper_html => { :class => 'grid_6 alpha' } %>
Edit 1:
From SimpleForm documentation:
Wrapper
SimpleForm allows you to add a wrapper which contains the label, error, hint and input. The first step is to configure a wrapper tag:
SimpleForm.wrapper_tag = :p
And now, you don't need to wrap your f.input calls anymore:
<%= simple_form_for #user do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<%= f.button :submit %>
<% end %>
Edit 2:
And there is this config option with which you can say what css class to use with the wrapper elements:
config/initializers/simple_form.rb
# CSS class to add to all wrapper tags.
config.wrapper_class = :input