Remove the default :size from form.text_field method - ruby-on-rails

I see myself writing a lot of :size => nil for f.text_field as so:
<%= f.text_field :street_address, :size => nil %>
<%= f.text_field :post_code, :size => nil %>
<%= f.text_field :city, :size => nil %>
Which is just dumb. Without the :size => nil above, text_field renders an <input> with a size="some number" (usually size="30") which I don't need or want there.
So, how can I implement DRY and make it so that f.text_field would not generate the size=30 or size="some number" attribute by default? This way I can avoid always having to type :size => nil.

All default field options are stored in one hash. It defaults to the following:
# action_view/helpers/form_helper
DEFAULT_FIELD_OPTIONS = { "size" => 30 }
You can delete "size" from it in an initializer, for example.
ActionView::Helpers::InstanceTag::DEFAULT_FIELD_OPTIONS.delete("size")

Rails extends Object class with with_options method. You can take advantage of it:
<%= form_for :foo do |f| %>
<% f.with_options :size => nil do |f_nil| %>
<%= f_nil.text_field :street_address %>
<%= f_nil.text_field :post_code %>
<%= f.text_field :city %> <!-- you can use old f here too! -->
<% end %>
<% end %>
Gives:
<input id="foo_street_address" name="foo[street_address]" type="text" />
<input id="foo_post_code" name="foo[post_code]" type="text" />
<input id="foo_city" name="foo[city]" size="30" type="text" /> <!-- you can use old f here too! -->

Try encapsulating the text_field like so:
def no_size_text_area(form, method) form.text_area(method, {:size => nil}) end
put the function in your helper file.
and using no_size_text_area in its place like so:
no_size_text_area(f,:city)

The Rails Team has since removed these defaults as of version 4.0.x. There is no way to set global defaults anymore either. The only easy solution is to use CSS to set the dimensions.

Related

Rails 4: text_field for acts_as_taggable_on not separating tags with a comma

I am trying to get the text_field in my form partial to comma-separate acts_as_taggable_on tags. Right now, when I reload the page, the commas disappear so if a field has two or more tags, they become one big tag instead. For instance, I get "Tag1 Tag2 Tag3" instead of "Tag1, Tag2, Tag3". I am using acts-as-taggable-on 3.4.2.
Here is my _form.html.erb partial:
<h2>Tags:</h2>
<p>Please separate the tags with a comma ','</p>
<% #article.tag_types.each do |tag| %>
<div class="form-group">
<strong><%= label_tag tag.to_s.titleize %></strong><br />
<%= f.text_field "#{tag.to_s.singularize}_list".to_sym, :placeholder => "Comma-separated list of #{tag.to_s}", class: 'form-control' %>
</div>
<% end %>
Every time I reload the edit page, the input value somehow removes the commas from the already-present tags, so the text field looks like this:
<input id="article_country_list" class="form-control" type="text" name="article[country_list]" value="China U.S.A." placeholder="Comma-separated list of countries">
instead of having value="China, U.S.A." as it should be.
Here is my model, article.rb:
class Article < ActiveRecord::Base
acts_as_taggable_on :people, :cities, :countries, :other
end
Any help would be much appreciated :)
Thanks!
Apparently this is a new security feature.
I solved the comma separation issue by doing:
<% #article.tag_types.each do |tag| %>
<div class="form-group">
<strong><%= f.label tag.to_s.titleize %></strong><br />
<% tag_sym = "#{tag.to_s.singularize}_list".to_sym %>
<% tag_list = "#{tag.to_s.singularize}_list" %>
<%= f.text_field tag_sym, value: #article.send(tag_list).to_s, :placeholder => "Comma-separated list of #{tag.to_s}", class: 'form-control' %>
</div>
<% end %>
Thanks! Since I am using ActiveAdmin with Formtastic I made a custom input.
So I created a new class: app/inputs/tag_list_input.rb with:
class TagListInput < Formtastic::Inputs::StringInput
def input_html_options
super.merge(:value => "#{#object.send(method).to_s.html_safe}")
end
end
and using this like:
f.input :some_tag_list, :as => :tag_list, :label => "SomeTags"

Simple Form #input_field method

Using a new/unchanged installation of simple_form 3.0.0.rc on rails 4.0.0.rc1, this view code
<%= simple_form_for #order do |f| %>
<%= f.input_field :email %>
<%= end %>
produces this output
<input class="string email optional" id="order_email" maxlength="255" name="order[email]" size="255" type="text" />
but I had expected the output not to include maxlength and to set type to 'email', much like the #input method does:
<input class="string email optional" id="order_email" name="order[email]" type="email" />
My expectations come from the fact that simple_form.rb includes the following default values:
b.use :html5
b.optional :maxlength
What do I need to do to make the input attributes from #input_field default to the same as #input?
Input field helper method will take hash you pass to it in second argument and turn them info html attributes. Look at the code below, should do the trick:
<%= simple_form_for #order do |f| %>
<%= f.input_field :email, :type => :email, :maxlength => nil %>
<% end %>
According to the docs input_field method takes all the options as input_html option except :as, :collection, :label_method, :value_method keys. I tried adding :as => :email but no avail. But you could use :type => :email to get type="email" in the rendered html. And according to the source of the method it uses some defaults as well.
So for getting the email field:
<%= simple_form_for #order do |f| %>
<%= f.input_field :email, :type => :email %>
<% end %>
I think its related to your database field... I think you have set the databasefield as string, which hast 255 maximum length in general.. This could be the reason why it adds 255 automatically?

Rails 3: Changing input box length

Using Rails 3 with Twitter Bootstrap and Simple_form, I am having issues changing the length of the input box in this field:
<div class="input-prepend input-append">
<%= f.input :price, :wrapper => :append do %>
<span class="add-on">$</span>
<%= f.input_field :price %>
<span class="add-on">.00</span>
<% end %>
</div>
Others say to add this after the :price variable:
:input_html => {:size => 15}
The 'do' loop seems to change the rules, any suggestions?
try
:style => "width: 100px;"
Twitter bootstrap has css classes for this. Depending on what size you want you can add class input-min, input-small, input-large and so on. You can also use the span classes, e.g. span1, span2, etc.
<div class="input-prepend input-append">
<%= f.input :price, :wrapper => :append do %>
<span class="add-on">$</span>
<%= f.input_field :price, :class => 'input-medium' %>
<span class="add-on">.00</span>
<% end %>
</div>
I am using the f.input form to create controls with labels in a :class => 'form-horizontal' form, using a class attribute or style attribute (directly or as a hash, any way I tried) didn't work for me, and had zero effect on the generated HTML.
This is what worked for me:
<%= f.input :description, input_html: { class: 'span12' } %>
This works with both the Bootstrap column layout classes ('span1', 'span2', etc,) the input sizing classes ('input-large', 'input-xxlarge', etc,) or whatever custom class you want. The trick is using the input_html key. You can also mess with the label using the label_html key but that's likely to mess up the form-horizontal layout.
It looks like the size key in :input_html => {**:size** => 15} is ignored by SimpleForm... when I tired this it did not affect the HTML output.
I found this here in the SimpleForm docs:
https://github.com/plataformatec/simple_form#usage

How do I change the html tag and class generated by fields_for?

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

Rails 3.1 - :fields_for, :child_index not incrementing

I have a nested attributes form with the following and am just learning how to use nested attributes. One problem I'm having is that the child_index values is not incrementing up. I'm getting 3 fields based upon the build in the controller but they all have 0 or 1 depending on what number is set to.
Any ideas on how to get this to increment?
# in controller: 3.times {#item.assets.build}
<% number = 1 %>
<div id='files'>
<%= f.fields_for :assets, :child_index => number do |asset| %>
<p>
number:<%= number %><br />
<%=asset.label :asset, "File ##{number += 1}" %>
<%= asset.file_field :asset %>
</p>
<% end %>
</div>
<%= f.submit %>
edit:
so all of them in html would have the form like:
item[assets_attributes][0][asset]
rather than the desired:
menu_item[assets_attributes][0][asset]
menu_item[assets_attributes][1][asset]
menu_item[assets_attributes][2][asset]
edit #2:
so looking through the source code, I see the following and am wondering if rails is supposed to be doing some auto-swapping and possibly this isn't happening;
<input id="item_assets_attributes_0_asset" name="item[assets_attributes][0][asset]" type="file" />
<input id="item_assets_attributes_0_id" name="item[assets_attributes][0][id]" type="hidden" value="1" />
Looking through the Rails source it's clear that if you specify :child_index there will be no auto-increment. Whether or not that is the proper behavior is debatable. If you completely omit the :child_index when calling fields_for, you should get the indexes you desire.
To get the correct label for each field you could use some JavaScript. If you don't like that, you could set the file number as an attribute of the Asset class.
class Asset < AR
attr_accessor :file_number
end
# in controller: 3.times {|n| #item.assets.build(:file_number => n) }
<div id='files'>
<%= f.fields_for :assets do |asset| %>
<p>
<%=asset.label :asset, "File ##{asset.file_number}" %>
<%= asset.file_field :asset %>
</p>
<% end %>
</div>
<%= f.submit %>

Resources