I have the following simple form:
<% form_for(#weight) do |f| %>
<%= f.error_messages %>
<%= f.label :weight %>:
<%= f.text_field :weight, :size => 5 %> kg.
<%= f.submit "Add weight" %>
<%= f.error_message_on :weight %>
<% end %>
which displays a form of only one field: weight.
Normally it renders like this:
<form action="/weights" class="new_weight" id="new_weight" method="post">
<div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="jYoVJkDnv4a1DMGnelJpGPElbH0XWKPNlESTt9GvzdA=" /></div>
<label for="weight_weight">Weight</label>:
<input id="weight_weight" name="weight[weight]" size="5" type="text" /> kg.
<input id="weight_submit" name="commit" type="submit" value="Add weight" />
</form>
which is fine. When I submit this form without setting any weight I get a validation error. f.error_messages and f.error_messages_on :weight correctly display the error messages, but the label and text field are not surrounded in a div with the class fieldWithError as I normally expect in forms in Rails. I instead get this:
<form action="/weights" class="new_weight" id="new_weight" method="post">
<div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="jYoVJkDnv4a1DMGnelJpGPElbH0XWKPNlESTt9GvzdA=" /></div>
<div class="errorExplanation" id="errorExplanation">
<h2>1 error prohibited this weight from being saved</h2>
<p>There were problems with the following fields:</p>
<ul><li>Weight can't be blank</li></ul>
</div>
<label for="weight_weight">Weight</label>:
<input id="weight_weight" name="weight[weight]" size="5" type="text" /> kg.
<input id="weight_submit" name="commit" type="submit" value="Add weight" />
<div class="formError">can't be blank</div>
</form>
For reference, what I've should have gotten is this:
<form action="/weights" class="new_weight" id="new_weight" method="post">
<div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="jYoVJkDnv4a1DMGnelJpGPElbH0XWKPNlESTt9GvzdA=" /></div>
<div class="errorExplanation" id="errorExplanation">
<h2>1 error prohibited this weight from being saved</h2>
<p>There were problems with the following fields:</p>
<ul><li>Weight can't be blank</li></ul>
</div>
<div class="fieldWithErrors"><label for="weight_weight">Weight</label></div>:
<div class="fieldWithErrors"><input id="weight_weight" name="weight[weight]" size="5" type="text" /></div> kg.
<input id="weight_submit" name="commit" type="submit" value="Add weight" />
<div class="formError">can't be blank</div>
</form>
Any ideas why I don't get those divs? I have formtastic installed and it's in use in other forms, but as far as I know that shouldn't interfere with this form.
Update: just to be sure, I printed out debug(#weight), it has the errors:
--- &id002 !ruby/object:Weight
attributes:
created_at:
updated_at:
weight:
measured_on: &id001 !timestamp
at: "2009-11-22 01:30:13.522589 +01:00"
"#marshal_with_utc_coercion": false
user_id: 1
attributes_cache:
measured_on: *id001
changed_attributes:
measured_on:
user_id:
errors: !ruby/object:ActiveRecord::Errors
base: *id002
errors:
weight:
- !ruby/object:ActiveRecord::Error
attribute: :weight
base: *id002
message: :blank
options: {}
type: :blank
new_record: true
Update: the model is
class Weight < ActiveRecord::Base
belongs_to :user
validates_presence_of :weight, :measured_on
attr_accessible :weight, :measured_on
def after_initialize
self.measured_on ||= Time.now
end
end
This is a bug in Formtastic. It was fixed but it seems that at this moment no released version of Formtastic has the fix.
My own bug report is on http://github.com/justinfrench/formtastic/issues/closed/#issue/132
The fix can be seen on http://github.com/grimen/formtastic/commit/2b81d9af385dadf8b37dc14f387afe3d43e4958a
Ultimately the problem was using justinfrench-formtastic from github, which is outdated and abandoned instead of formtastic from gemcutter.
You may need to enclose your label & field in a block tag like p or div.
<p>
<%= f.label :weight %>:
<%= f.text_field :weight, :size => 5 %> kg.
</p>
This way rails has a place to slip the error back into, else it falls back to the form as it is doing now.
Related
I am still learning RoR but I cant learn by following someone else's code. I have decided to implement by own app.
I have generated a scaffold and in the _form.html.erb I have this:
<div class="field">
<%= f.label :bath_accessories %><br>
<%= f.select :bath_accessories, options_for_select(["Shower", "Extractor Fan", "Lights", "Shaver", "Heat Rail"]) %><br>
</div>
When the user selects "Shower" from the above lists, I want to enable in view:
<div class="field">
<%= f.label :watts %><br>
<%= f.number_field :watts %>
</div>
I am lost where to put the if statement for: <%= f.select :bath_accessories, options_for_select(["Shower", "Extractor Fan", "Lights", "Shaver", "Heat Rail"]) %> But I did this and nothing shows:
<% if :bath_accessories[0] %>
# What to out put here with "<%= code %>?
Generated HTML Tag:
<form class="new_bathroom_accessory" id="new_bathroom_accessory" action="/bathroom_accessories" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="r9M+Q7Np+/i68gwj65JSvV8wi4+4yb5d6tFWBHMw8k9nz1oRHGzh7AZHOTFvlaiS2lmqTch356vVYNlh7Urifw==" />
<div class="field">
<label for="bathroom_accessory_bath_accessories">Bath accessories</label><br>
<select name="bathroom_accessory[bath_accessories]" id="bathroom_accessory_bath_accessories"><option value="Shower">Shower</option>
<option value="Extractor Fan">Extractor Fan</option>
<option value="Lights">Lights</option>
<option value="Shaver">Shaver</option>
<option value="Heat Rail">Heat Rail</option></select><br>
</div>
<div class="field">
<label for="bathroom_accessory_watts">Watts</label><br>
<input type="number" name="bathroom_accessory[watts]" id="bathroom_accessory_watts" />
</div>
<div class="field">
<label for="bathroom_accessory_volts">Volts</label><br>
<input type="number" name="bathroom_accessory[volts]" id="bathroom_accessory_volts" />
</div>
<div class="actions">
<input type="submit" name="commit" value="Create Bathroom accessory" />
</div>
</form>
By adding an id to particular <div>,you can control that <div> as per user selection.
<div class="field" id="shower_id">
<%= f.label :watts %><br>
<%= f.number_field :watts %>
</div>
And you need JavaScript or JQuery code like this
$('#bathroom_accessory_bath_accessories').on('change',function(){
if( $(this).val()==="Shower"){
$("#shower_id").show()
}
else{
$("#shower_id").hide()
}
});
DEMO
I have the layout presently using nested_form_for as:
with the code as simply:
<%= f.label :monday %>
<%= f.check_box :monday %>
<%= f.label :tuesday %>
<%= f.check_box :tuesday %>
<%= f.label :wednesday %>
<%= f.check_box :wednesday %>
<%= f.label :thursday %>
<%= f.check_box :thursday %>
But I would like if these attributes could like listed in a straight line with breaks such as:
Monday | Tuesday | Wednesday | Thursday ....
Is there a setting in nested_form_for to allow this?
Note below is the HTML generated from the first response
<hr>
<strong>Day(s) special Will Appear</strong>
<ul id="dayForm">
<label for="campaign_monday">Monday</label>
<input name="campaign[monday]" type="hidden" value="0" /><input id="campaign_monday" name="campaign[monday]" type="checkbox" value="1" />
<label for="campaign_tuesday">Tuesday</label>
<input name="campaign[tuesday]" type="hidden" value="0" /><input id="campaign_tuesday" name="campaign[tuesday]" type="checkbox" value="1" />
<label for="campaign_wednesday">Wednesday</label>
<input name="campaign[wednesday]" type="hidden" value="0" /><input id="campaign_wednesday" name="campaign[wednesday]" type="checkbox" value="1" />
<label for="campaign_thursday">Thursday</label>
<input name="campaign[thursday]" type="hidden" value="0" /><input id="campaign_thursday" name="campaign[thursday]" type="checkbox" value="1" />
<label for="campaign_friday">Friday</label>
<input name="campaign[friday]" type="hidden" value="0" /><input id="campaign_friday" name="campaign[friday]" type="checkbox" value="1" />
<label for="campaign_saturday">Saturday</label>
<input name="campaign[saturday]" type="hidden" value="0" /><input id="campaign_saturday" name="campaign[saturday]" type="checkbox" value="1" />
<label for="campaign_sunday">Sunday</label>
<input name="campaign[sunday]" type="hidden" value="0" /><input id="campaign_sunday" name="campaign[sunday]" type="checkbox" value="1" />
</ul>
Rails form_for helpers help you generate HTML; the HTML generated is still subject to the same rules as other HTML elements. Rails offers ways to add HTML/CSS to the form fields themselves, which may be what you are looking for. For example,
<%= f.label :monday, :class => 'inline' %>
The :class => 'inline' adds the class 'inline' to the HTML form element on the page and you can add styling thereafter to .inline {} in your css file.
But you could also simply do something like:
Wrap the form fields with a <ul> tag,
<ul id="dayForm">
<%= f.label :monday %>
<%= f.check_box :monday %>
<%= f.label :tuesday %>
<%= f.check_box :tuesday %>
<%= f.label :wednesday %>
<%= f.check_box :wednesday %>
<%= f.label :thursday %>
<%= f.check_box :thursday %>
</ul>
And in your css file,
ul#dayForm {
list-style: none;
}
ul#dayForm input {
display: list-item;
float: left;
width: 100px; /* adjust depending on desired size */
}
ul#dayForm label {
display: list-item;
float: left;
width: 100px; /* adjust depending on desired size */
}
To create the inline effect that you are looking for.
I'm going through Michael Hartl's Rails tutorial. One of the exercises for chapter 8 is to rewrite the code using form_tag instead of form_for. After viewing the source that form_for was giving me and looking up each tag in the Rails documentation, I was able to successfully put it together.
My question is: How does Rails know what id attribute to give the <input> tag created by text_field_tag, so that it matches the id of the <label> tag created by the label_tag that precedes it?
Here's the code for the form:
<%= form_tag(sessions_path) do %>
<%= label_tag "session_email", "Email" %>
<%= text_field_tag "session[email]" %>
<%= label_tag "session_password", "Password" %>
<%= password_field_tag "session[password]" %>
<%= button_tag("Sign in", name: "commit", type: "submit") %>
<% end %>
Here's the resulting html:
<form accept-charset="UTF-8" action="/sessions" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="c9a5KJveRSOQyDo/ckUtpmQAbjw2f1alnB6Dn1lu3XU=" /></div>
<label for="session_email">Email</label>
<input id="session_email" name="session[email]" type="text" value="{:id=>"session_email"}" />
<label for="session_password">Password</label>
<input id="session_password" name="session[password]" type="password" value="{:id=>"session_password"}" />
<button name="commit" type="submit">Sign in</button>
Note that since Rails 5.1, the recommended form helper to use is form_with.
And form_with no longer automatically generates id's and class's for DOM elements any more like form_for and form_tag used to.
This has implications for adding markup like labels which used to link up to their corresponding input fields automatically. Now, for a label to properly pair up to an input field (with the for attribute) you need to explicitly add the id attribute to the input.
Example
ERB:
<%= form_with model: User.new do |f| %>
<%= f.label :name %>
<%= f.text_field :name, id: :user_name %>
<% end %>
which generates HTML:
<form action="/users" method="post">
<label for="user_name">Name</label>
<input id="user_name" type="text" name="user[name]">
</form>
See also
https://medium.com/#tinchorb/form-with-building-html-forms-in-rails-5-1-f30bd60ef52d, specifically the heading "No more auto-generated ids and classes".
I have two rails apps, and the 'form-horizontal' is working in one, but not the other, and I have no idea why.
First app is called "Horizontal" (my test app) and the other is "Inventory"
Form in "horizontal" app:
<%= simple_form_for(#part, html: {class: 'form-horizontal' }) do |f| %>
<div class="field">
<%= f.input :name %>
</div>
<div class="field">
<%= f.input :number %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and looks like this in the browser:
and the form for the "inventory" app is:
<%= simple_form_for(#item, html: {class: 'form-horizontal' }) do |f| %>
<%= f.error_notification %>
<div class="field">
<%= f.input :part_number %>
</div>
<div class="field">
<%= f.input :on_order_qty %>
<%= f.input :revision %>
<%= f.input :current_rev %>
<%= f.input :name, required: false%><br>
</div>
<%= f.simple_fields_for :parts do |part| %>
<%= render 'part_fields', :f => part %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add additional supplier', f, :parts %><br><br>
</div>
<div class="fields">
<%= f.input :stock_qty %>
<%= f.input :ncmr_qty %>
</div>
<div class="form-actions">
<%= f.submit %>
</div>
<% end %>
but it looks like this in the browser:
Why won't the form-horizontal class work in the "Inventory" app?
It appears that the integer input fields are getting rendered horizontally, but something weird is happening in the text input fields. Here is the source html from the browser for the "Inventory" app:
<form accept-charset="UTF-8" action="/items" class="simple_form form-horizontal"
id="new_item" method="post"><div style="margin:0;padding:0;display:inline"><input
name="utf8" type="hidden" value="✓" /><input name="authenticity_token"
type="hidden" value="H3DKGhGdtfv1e8F1rg9TgDJUyaBspXOSFMpm2gnjwzk=" /></div>
<div class="field">
<div class="input string required item_part_number"><label class="string required"
for="item_part_number"><abbr title="required">*</abbr> Part number</label><input aria
required="true" class="string required" id="item_part_number" maxlength="255"
name="item[part_number]" required="required" size="255" type="text" /></div>
</div>
<div class="field">
<div class="input integer optional item_on_order_qty"><label class="integer optional"
for="item_on_order_qty">On order qty</label><input class="numeric integer optional"
id="item_on_order_qty" name="item[on_order_qty]" step="1" type="number" /></div>
<div class="input string optional item_revision"><label class="string optional"
for="item_revision">Revision</label><input class="string optional" id="item_revision"
maxlength="255" name="item[revision]" size="255" type="text" /></div>
<div class="input boolean optional item_current_rev"><input name="item[current_rev]"
type="hidden" value="0" /><input class="boolean optional" id="item_current_rev"
name="item[current_rev]" type="checkbox" value="1" /><label class="boolean optional"
for="item_current_rev">Current rev</label></div>
<div class="input string optional item_name"><label class="string optional"
for="item_name">Name</label><input class="string optional" id="item_name" maxlength="255"
name="item[name]" size="255" type="text" /></div><br>
</div>
( I took out the html for the nested fields and some other fields for brevity)
<div class="form-actions">
<input name="commit" type="submit" value="Create Item" />
</div>
</form>
I've tested in both Chrome and Firefox. I've checked that the bootstrap-sass gem and simple_form gem are the same versions. I have no fancy customization css or javascript, just the #import 'bootstrap'; line in a bootstrap_custom.css.scss file in both apps. I don't know why the text input fields cover the whole width of the screen in the "Inventory" app, but the integer fields seem to be fine and rendering horizontally. What's wrong here?
I ran into a similar issue and found a pretty quick fix here http://www.iconoclastlabs.com/blog/using-twitter-bootstrap-3-with-simple_form
The simple fix is (after doing the normal simple form bootstrap init stuff -see below), you add the following code to an initializer (like config/initializers/simple_form_bootstrap.rb)
inputs = %w[
CollectionSelectInput
DateTimeInput
FileInput
GroupedCollectionSelectInput
NumericInput
PasswordInput
RangeInput
StringInput
TextInput
]
inputs.each do |input_type|
superclass = "SimpleForm::Inputs::#{input_type}".constantize
new_class = Class.new(superclass) do
def input_html_classes
super.push('form-control')
end
end
Object.const_set(input_type, new_class)
end
and you are off to the races.
The "normal simple form bootstrap init stuff" goes something like:
rails generate simple_form:install --bootstrap
If you want horizontal forms, add this to your simple_form config
config.form_class = "simple_form form-horizontal"
CAVEAT: Based on some recent comments, it appears this many not work for more recent versions of simple_form. I wrote the post some time ago and the project that was using this code (for me) is no longer using simple_form so it's hard to track down the exact version number. I believe this will work for verisions 2.x. Once you get to v3 you may have issues and have to find a different solution.
To override on per form basis, change:
<%= simple_form_for(#item, html: {class: 'form-horizontal' }) do |f| %>
to
<%= simple_form_for(#item, wrapper: :horizontal_form) do |f| %>
to change all forms to horizontal, change initializer:
config/initializers/simple_form_bootstrap.rb line:
config.default_wrapper = :vertical_form
to
config.default_wrapper = :horizontal_form
(remember to restart rails server after changing initializer)
to change just an individual input, change:
<%= f.input :on_order_qty %>
to
<%= f.input :on_order_qty, wrapper: :horizontal_form %>
Simple Form 3.1.0.rc1 has been released!! This supports bootstrap 3. Just update your gem to the latest version this will solve your problem. You can check the other enhancements through the change logs here https://github.com/plataformatec/simple_form/blob/v3.1.0.rc1/CHANGELOG.md
Just update your simple_form to
gem 'simple_form', '3.1.0.rc2'
And then re-run
$ rails generate simple_form:install --bootstrap
I tried quite many different solutions but, nothing helped until I've added wrapper: :horizontal_form line to each form inputs. And, I have the latest simple_form version: 3.2.1
For example:
= f.input :payment_term, wrapper: :horizontal_form
Hint: https://gist.github.com/chunlea/11125126/
Use simple form RC1. There is an entire example project: https://github.com/rafaelfranca/simple_form-bootstrap . I've just copied bootstrap initializer and followed horirozontal view example at https://github.com/rafaelfranca/simple_form-bootstrap/tree/master/app/views/examples.
If all the above doesn't work try gem
gem 'simple_form_bootstrap3'
Need to replace form_for with horizontal_form_for
Please check out the very helpful sample app here for usage of Simple Form and the Bootstrap toolkit on a Rails 4 application.:
http://simple-form-bootstrap.plataformatec.com.br/
Don't forget the docs page.
I had an issue with the full length of the input field spanning my entire page. Here is what I did and I hope it helps someone else.
Using simple_form 3.4.0
Open config/initializers/simple_form_bootstrap.rb
At the bottom of the page I changed the following:
From
config.default_wrapper = :vertical_form
config.wrapper_mappings = {
check_boxes: :vertical_radio_and_checkboxes,
radio_buttons: :vertical_radio_and_checkboxes,
file: :vertical_file_input,
boolean: :vertical_boolean,
datetime: :multi_select,
date: :multi_select,
time: :multi_select
}
end
To:
config.default_wrapper = :horizontal_form
config.wrapper_mappings = {
check_boxes: :horizontal_radio_and_checkboxes,
radio_buttons: :horizontal_radio_and_checkboxes,
file: :horizontal_file_input,
boolean: :horizontal_boolean,
datetime: :multi_select,
date: :multi_select,
time: :multi_select
}
end
Then restart your app to reinitialize.
When i use form-horizontal in my code, i also modify the different inputs with the bootstrap classes. For exemple with bootstrap 3:
<div class="form-group">
<%= f.label :name, class: "control-label col-sm-3" %>
<div class="col-sm-4"><%= f.text_field :name, placeholder: "Your placeholder", class: "form-control" %></div>
</div>
And now you can adjust the col-sm to col-sm-12 if you want the entire width of your app. I think it's easier to customize this way. ( col-sm are for bootstrap 3, if you need older version i think you have to use the old span- notation)
More info for bootsrap form here: doc
Here is an exemple of code with bootstrap 2 and simple form: doc
The output form with bootsrap 2 should look like this:
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="inputName">Name</label>
<div class="controls">
<input type="text" id="Name" placeholder="Name">
</div>
</div>
</form>
I think you need to set a control-group class div and a controls class div.
Here is the doc form the old syntax: doc
Hope it helps
I have a standard rails form_for tag for creating and editing a new hotel. This renders just fine when visited via the edit_hotels_path, however when visting the new_hotels_path the html form tag is being set to display: none; causing the form to not show only in the "new" view.
I have restarted the server, emptied the cache, made sure they are using the same CSS but it still renders with display set to none.
Here are the styles as seen using developer tools
<form accept-charset="UTF-8" action="/hotels" class="new_hotel" id="new_hotel" method="post" style="display: none; "><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"><input name="authenticity_token" type="hidden" value="pDlR3gV2tm+Z7xRFdC0uclNY13FlzxUSOjOrHs2ttO0="></div>
element.style {
display: none;
}
below is the html source being rendered, which doesn't include display: none;
<form accept-charset="UTF-8" action="/hotels" class="new_hotel" id="new_hotel" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="pDlR3gV2tm+Z7xRFdC0uclNY13FlzxUSOjOrHs2ttO0=" /></div>
<div class="control-group">
<div class="controls">
<input id="hotel_name" name="hotel[name]" placeholder="Name..." size="30" type="text" /><br>
<select id="hotel_year" name="hotel[year]"><option value="2012">2012</option>
<option value="2013">2013</option>
<option value="2014">2014</option>
<option value="2015">2015</option></select><br>
<select id="hotel_month" name="hotel[month]"><option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
<option value="October">October</option>
<option value="November">November</option>
<option value="December">December</option></select><br>
<textarea cols="40" id="hotel_body" name="hotel[body]" placeholder="Hotel info up to 1000 words..." rows="20">
</textarea><br>
<input id="hotel_meta_tags" name="hotel[meta_tags]" placeholder="Enter meta tags for image, as a comma separated list..." size="30" type="text" /><br>
<legend>Winner</legend>
<input name="hotel[winner]" type="hidden" value="0" /><input id="hotel_winner" name="hotel[winner]" type="checkbox" value="1" />
<br/>
</div>
<div class="form-actions">
<input class="btn-large btn-success" name="commit" type="submit" value="create" />
</div>
</div>
</form>
below is the code, would appreciated any help.
_form.html.erb
<%= form_for #hotel do |f| %>
<% if #hotel.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#hotel.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #hotel.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render partial: "shared/code_sheet" %>
<div class="control-group">
<div class="controls">
<%= f.text_field :name, placeholder: "Name..." %><br>
<%= f.select :year, [2012, 2013, 2014, 2015] %><br>
<%= f.select :month, ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] %><br>
<%= f.text_area :body, placeholder: "Hotel info up to 1000 words..." %><br>
<%= f.text_field :meta_tags, placeholder: "Enter meta tags for image, as a comma separated list..." %><br>
<legend>Winner</legend>
<%= f.check_box :winner %>
<br/>
</div>
<div class="form-actions">
<%= f.submit "create", class: "btn-large btn-success" %>
</div>
</div>
<% end %>
edit.html.erb
<div class="container">
<h1>Editing hotel</h1>
<%= render "form" %>
<%= link_to 'hotels index', hotels_path %>
</div>
new.html.erb
<div class="container">
<h1>New hotel</h1>
<%= render "form" %>
<%= link_to 'hotels index', hotels_path %>
</div>
It could be anything. You must know what is in your CSS. Did you search for 'display: none;' in your CSS files and checked the matches? element.style is usually set directly on the HTML tag. Search the view also place debugging string to make sure it is pulling the appropriate .html.