Rails forms using collection_radio_buttons on array instead of objects - ruby-on-rails

Rails has a form helper f.collection_radio_buttons which operates very similar to the f.collection_select form helper.
However, f.colleciton_radio_buttons only works on collections of objects and doesn't work with a simple array.
As an example, I can have:
<%= f.select :attribute, ["First", "Second"] %>
But there isn't any:
<%= f.radio_buttons :attribute, ["First", "Second"] %>
So to make f.collection_radio_buttons work with a simple array I have to do:
<%= f.collection_radio _buttons :attribute, ["First", "Second"], :to_s, :to_s %>
This "works" but it seems very hacky. Is there a cleaner way to reference the value of an array instead of calling .to_s on it?

Maybe this is an old post but if it is helpful for somebody else then here it is. Now in 2019, I'm working with Rails 5 application and I have a form where I had to show two radio buttons for a given attribute.
I a helper method I have:
def get_company_segments
company = current_user.branch.company
[
[company.various_segment_fee, 'various', 'Varios'],
[company.metal_segment_fee, 'metal', 'Metal']
]
end
Output:
#=> [["12.6", "various", "Varios"], ["10", "metal", "Metal"]]
Then in my form view I have something like:
<%= form.collection_radio_buttons(:segment, get_company_segments, :second, :last) do |segment| %>
<div class="form-check form-check-inline">
<%= segment.radio_button(class: 'form-check-input', id: "agreement_segment_#{segment.object.second}" %>
<%= segment.label(class: 'form-check-label', for: "agreement_segment_#{segment.object.second}") %>
</div>
<%- end %>
And it renders something like this:
And the HTML looks like this:
<div class="form-check custom-radio form-check-inline">
<input class="form-check-input" id="agreement_segment_various" data-fee="12.6" type="radio" value="various" name="agreement[segment]">
<label class="form-check-label" for="agreement_segment_various">Varios</label>
</div>
<div class="form-check custom-radio form-check-inline">
<input class="form-check-input" id="agreement_segment_metal" data-fee="10" type="radio" value="metal" name="agreement[segment]">
<label class="form-check-label" for="agreement_segment_metal">Metal</label>
</div>
I hope it could be a good reference for anyone else. 👻

Related

Rails best_in_place gem with Material Design Lite

Im trying to incorporate the best_in_place gem and got everything working, but now Im trying to get it to use material design lite to style the input when it is clicked.
Here is the html for the view:
<h2><%= best_in_place #user, :displayname, :as => :input %></h2>
And this is what the html would be for a normal text input with MDL:
<div class="mdl-textfield mdl-js-textfield">
<input class="mdl-textfield__input" type="text" id="sample1">
<label class="mdl-textfield__label" for="sample1">Text...</label>
</div>
Cant figure out what options to make this work with the best_in_place gem
I dont have the "best_in_place gem".
This is a solution I used to style a form containing an email input. I replaced the entire MDL "input" line. You would have to replace the "id"/ "for" relation and email field to something relevant to your purpose. You may have to fiddle around. Hope it points you in the right direction.
<%= form_for(#user) do |f| %>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<%= f.email_field :email, class:'mdl-textfield__input', type:'text', id:'email' %>
<label class="mdl-textfield__label" for="email">EMAIL</label>
</div>
<% end %>

Why is Rails not capturing one of my submitted form parametesr in my controller?

I'm using Rails 4.2.3 with MySql 5.5.37. I recently change the name and type of my column and now when I submit my Rails form that form field, "selection_id," is not getting captured. Below is my Rails form ...
<div class="field">
<%= f.label :day %><br>
<%= f.hidden_field :day, :validate => true %>
<div id="datepicker"></div>
</div>
<div class="field">
<%= f.label :selection_id %><br>
<div class="styled-select"><%= collection_select(:user_selection, :selection_id, #selections, :id, :description, {:prompt => true}) %></div>
</div>
<div class="field">
<%= f.label :total %><br>
<%= f.text_field :total, :size => 4, :validate => true %>
</div>
And here is the HTML that gets output to the browser ...
<div class="field">
<label for="user_selection_day">Day</label><br>
<input validate="true" type="hidden" value="02/07/2016" name="user_selection[day]" id="user_selection_day" />
<div id="datepicker"></div>
</div>
<div class="field">
<div class="field_with_errors"><label for="user_selection_selection_id">selection</label></div><br>
<div class="styled-select"><div class="field_with_errors"><select name="user_selection[selection_id]" id="user_selection_selection_id"><option value="">Please select</option>
<option value="3">option 1</option>
<option value="4">option 2</option></select></div></div>
</div>
<div class="field">
<label for="user_selection_total">Total</label><br>
<input size="4" validate="true" type="text" value="1" name="user_selection[total]" id="user_selection_total" />
</div>
I can see this data getting submitted in Chrome ...
user_selection[day]:02/19/2016
user_selection[selection_id]:3
user_selection[total]:9
but on my controller side, when I try and output the params, only two of the three are printing out. This "puts"
def create
#current_user = User.find(session["user_id"])
...
puts user_selection_params
prints
{"day"=>"02/19/2016", "total"=>"9"}
Why is this other field getting lost and how can I fix it?
You are having this problem because #object_id is a method defined on Object, the class that all Ruby objects extend. In other words, it's reserved by Ruby itself and can't be used when naming database fields / model attributes. You're going to have to rename that column/association to something else.
As a side note, it's not idiomatic Ruby to include the word "Object" in your class name. Arguably the class should just be named User, instead of UserObject.
Reference: http://ruby-doc.org/core-2.3.0/Object.html#method-i-object_id
Please don't use object_id in your model.
There should be no column named object_id in the database.
object_id is a default methods that all (except BasicObject in Ruby 1.9) objects have ...
(see docs).

Defining field label in a block - on error, field_with_errors div tag not in right place

I am using validates_acceptance_of :terms, :message => "must be accepted" in my user.rb model, and am using bootstrap-sass.
My check box code looks like this in the view:
<div class="control-group">
<%= f.label :terms, :class => "control-label" do %>
Accept <%= link_to('Terms of Use *', "#myTOUModal", :"data-toggle" => "modal") %>
<% end %>
<div class="controls">
<%= f.check_box :terms %>
</div>
</div>
For some reason, when the terms check box isn't selected on form submission, the appropriate error message shows up at the top of the form, but there is a problem with the field_with_errors div class wrapping around the check box label.
The HTML for the rendered page looks like this:
<div class="control-group">
<label class="control-label" for="user_terms">
Accept Terms of Use *
</label>
<div class="controls">
<input name="user[terms]" type="hidden" value="0" />
<div class="field_with_errors">
<input id="user_terms" name="user[terms]" type="checkbox" value="1" />
</div>
</div>
</div>
The result is that the check box field label isn't highlighted on error. Is there a way to force the div tag placement for the field_with_errors class to show up just after the <div class="control-group"> tag? Why does using a block to define a field label throw off the field_with_errors tag placement? Does anyone have experience with this?
Thank you
This is a bug i think. The problem is in block. Define your label without block and everything works.
Try something like:
<% modal_html = capture do >
Accept <%= link_to('Terms of Use *', "#myTOUModal", :"data-toggle" => "modal") %>
<% end %>
<%= f.label :terms, modal_html, :class => "control-label" %>
Or helper:
def modal_html
#Q{Accept #{link_to('Terms of Use *', "#myTOUModal", :"data-toggle" => "modal")} }.html_safe
end

Simple_form bootstrap style inline-form not working properly

I have a working twitter bootstrap install and simple form generates the following:
<form accept-charset="UTF-8" action="/find_map" class="simple_form form-inline" id="new_location" method="post" novalidate="novalidate"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="p5CSoidWaoGMfHY0/3ElWi0XJVg6Cqi9GqWRNlJLBQg=" /></div>
<div class="control-group string required"><div class="controls"><input class="string required" id="location_address" name="location[address]" placeholder="Address" size="50" type="text" /></div></div><input class="btn" name="commit" type="submit" value="Find!" />
</form>
Somehow the "Find!" button won't appear on the same line as the search box. Any ideas?
Thanks!
UPDATE:
Sorry I should have mentioned that all the markup is generated by simple_form based on the following:
<%= simple_form_for #location, :url => find_map_path, :html => { :class => 'form-inline' } do |f| %>
<%= f.input :address, :label => false, :placeholder => "Address" %>
<%= f.submit "Find!", :class => 'btn' %>
<% end %>
So, really, there seems to be an issue with the generated markup, even though I have run the bootstrap install for simple_form, etc.
The above image shows a straight html form
<form class="form-inline">
<input type="text" class="input-small" placeholder="Email">
<button type="submit" class="btn">Sign in</button>
</form>
...above the one generated by simple_form.
I think there are a couple issues here. One is the formatting, and the way simple_form adds a <div> around the input field. #Ron's suggestion of using input_field works for me with simple_form 2.0.1. My example is searching for name in a Contacts table. The following makes the text box and button appear side by side:
<%= simple_form_for :contact, :method => 'get',
:html => { :class => 'form-search' } do |f| %>
<%= f.input_field :search, :placeholder => "Name",
:class => "input-medium search-query" %>
<%= f.submit "Find!", :class => "btn" %>
<% end %>
The other issue is that it seems simple_form usually assumes you want to work with model and field names. The example above uses a :symbol instead of a #model as the first argument as suggested here. But that still generates an input field named contact[search] so you'd have to tell your controller how to deal with that.
I think in this case it may be simpler to not use simple_form and instead use something like the form near the beginning of Ryan Bates' Railscast #240, Search, Sort, Paginate with AJAX:
<%= form_tag contacts_path, :method => 'get', :class => "form-search" do %>
<%= text_field_tag :search, nil, :placeholder => "Name",
:class => "input-medium search-query" %>
<%= submit_tag "Find!", :name => nil, :class => "btn" %>
<% end %>
Now the field is just named "search" and I can consume it in my controller's #index method something like this:
#contacts = #contacts.search(params[:search])
assuming I have this in my model:
def self.search(search)
if search
where('lower(name) LIKE ?', "%#{search.downcase}%")
else
scoped
end
end
It's creating subforms because you're passing input to simple_form. Use input_field instead. (BTW, this also works with simple_fields_for).
You need to customize the control-group and controls div classes to display as inline-block when they are under a form-inline form:
form.form-inline div.control-group { display: inline-block; }
form.form-inline div.control-group div.controls { display: inline-block; }
Adding to Mark's reply:
So, input_field exists to create the input component only, it won't give you any sort of label/error/wrapper. That means you won't get any or tag wrapping the field, you should do that manually in case you want to.
Now about using the form with an object, SimpleForm is a FormBuilder, which means it was created to work with a namespace, either an object or a symbol. SimpleForm's simple_form_for == Rails' form_for, you always need an object namespace to work with.
For such a simple case as a search form, you're better off with simple form helpers such as form_tag, as you've pointed out. There's no need to rely on simple_form_for or form_for for that, I agree and I usually go down that path.
I hope that helps, let me know if you still have doubts.
Change the :html => { :class => 'form-inline' } to :html => { :class => 'form-horizontal' }
can't you move the input button next to input address? I think it will solve the problem
<form accept-charset="UTF-8" action="/find_map" class="simple_form form-inline" id="new_location" method="post" novalidate="novalidate">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="p5CSoidWaoGMfHY0/3ElWi0XJVg6Cqi9GqWRNlJLBQg=" />
</div>
<div class="control-group string required">
<div class="controls">
<input class="string required" id="location_address" name="location[address]" placeholder="Address" size="50" type="text" />
<!-- move the button to here -->
<input class="btn" name="commit" type="submit" value="Find!" />
</div>
</div>
</form>
Please, all people with this problem, don't use fluid layout and be sure you are specifying the HTML5 doctype to the documents.

Rails Validation | add class to surrounding <div>

Rails question. The default behavior for error validation is to fieldWithError-styled div around the input field like the following
<div class="type-text" id="pre_negotiation_value_div">
<label for="contract_budget_holder">Budget Holder</label>
<div class="fieldWithErrors">
<input id="contract_budget_holder"name="contract[budget_holder]" size="30" type="text" value="" />
</div>
</div>
What I am trying to accomplish is, to surround the label AND the input field with a classed div tag, so to look like the following:
<div class="type-text fieldWithErrors" id="pre_negotiation_value_div">
<label for="contract_budget_holder">Budget Holder</label>
<input id="contract_budget_holder"name="contract[budget_holder]" size="30" type="text" value="" />
</div>
Any ideas how to accomplish this? Can you hook up javascript into ActionView::Base.field_error_proc?
I am new to Rails, I apologize if this is super easy!
Thanks for your help.
Jonathan
It's not super easy to do exactly what you want, but if you have ERB like this:
<div id="pre_negotiation_value_div" class="type-text">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
You will get HTML like this:
<div id="pre_negotiation_value_div" class="type-text">
<div class="fieldWithErrors"><label for="foo_name">Name</label></div>
<div class="fieldWithErrors"><input id="foo_name" name="foo[name]" size="30" type="text" value="" />
</div>
Where both the label and the text_field will have the fieldWithErrors div around them. Depending on how you want to style it, that might be good enough. If it's not good enough, you'll have to do a custom helper like this:
class ActionView::Helpers::FormBuilder
def labeled_input(method, options={}, &block)
(options[:class] ||= "") << " fieldWithErrors" if #object.errors.on(method)
ActionView::Helpers::InstanceTag.send(:alias_method, :original_error_wrapping, :error_wrapping)
ActionView::Helpers::InstanceTag.send(:define_method, :error_wrapping,
Proc.new {|html_tag, has_error| html_tag})
#template.concat(#template.content_tag(:div, #template.capture(&block), options))
ensure
ActionView::Helpers::InstanceTag.send(:alias_method, :error_wrapping, :original_error_wrapping)
ActionView::Helpers::InstanceTag.send(:remove_method, :original_error_wrapping)
end
end
Put that in config/initializers/labeled_input.rb. It's a bunch Ruby meta-foo, but what it does is put the "fieldWithErrors" class on the outer div. It temporarily re-defines the error_wrapping method of InstanceTag so that the inner label and text_field tags don't have the "fieldWithErrors" div surrounding them. You use it in ERB like this:
<% f.labeled_input :name, :id => "pre_negotiation_value_div", :class => "type-text" do %>
<%= f.label :name %>
<%= f.text_field :name %>
<% end %>
RAILS 3 UPDATE
I'm updating my app to rails 3. If you've used this method and are upgrading you'll get some deprecation warnings and form fields appearing twice or several times.
To fix these:
1) Change the line in labeled_input.rb that checks for errors. This stops deprecation warnings accessing errors:
(options[:class] ||= "") << " fieldWithErrors" unless #object.errors[method].empty?
2) Change the line in labeled_input.rb before the 'ensure'. This stops form elements appearing multiple times:
#template.content_tag(:div, #template.capture(&block), options)
3) In your view files where you call labeled_input, use <%= rather than <%. This prevents deprecation warnings.
Hope that saves you some time.

Resources