How can I DRY this <div> with Rails Forms? - ruby-on-rails

I understand that with Rails Form Helpers, I can pass in classes, placeholders, types, etc. into Rails, so instead of writing
<input id="name" name="name" type: "text" pattern="" value="Kanye West"/>
<label class="mdl-textfield__label" for="name">Enter Name</label>
I can do:
<%= f.text_field :name, class: 'mdl-textfield__input', type: 'text', pattern: '-?[0-9]*(\.[0-9]+)?', id: 'name', value: 'Kanye West' %>
<label class="mdl-textfield__label" for="name">Enter Name</label>
But it becomes pointless, because if I use a CSS framework, it ends up looking like this...
<div class="mdl-cell mdl-cell--6-col mdl-cell--4-col-tablet hide-dis">
<div class="mdl-textfield advanced-input mdl-js-textfield mdl-textfield--expandable">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<%= f.text_field :name, class: 'mdl-textfield__input', type: 'text', pattern: '-?[0-9]*(\.[0-9]+)?', id: 'name', value: 'Kanye West' %>
<label class="mdl-textfield__label" for="name">Enter Name</label>
</div>
</div>
</div>
You can imagine how ugly this can get when you have 10 form elements, right. I could try partializing it, but I don't know how I would pass in the f.textfield part. Please let me know how I can improve this mess and or anything else that you see that can be improved with me code :)

You can create your own FormBuilder and create custom controls that include the wrapper classes than you need.
For example if you want to wrap your text fields in a particular div:
class CustomFormBuilder < ActionView::Helpers::FormBuilder
def custom_text_field(method, tag_value, options = {})
#template.content_tag(:div,
#template.text_field(
#object_name, method, tag_value, objectify_options(options)
),
class: 'mdl-textfield mdl-js-textfield'
)
end
end

Related

Rails forms using collection_radio_buttons on array instead of objects

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. 👻

Rails form helper: Radio Button doesn't take css-class name

I have a Rails form helper and want to add a css-class to a radio button input field.
<span class="input-nile">
<%= f.radio_button :nile_administration, class: 'input__field input__field-nile radio' %>
<label class="radio-label">Nile Administration</label>
</span>
The output is
<span class="input-nile">
<input type="radio" value="{:class=>"input__field input__field-nile radio"}" name="user[nile_administration]" id="user_nile_administration_classinput__field_input__field-nile_radio">
<label class="radio-label">Nile Administration</label>
</span>
I want to achieve that the input tag of type radio get the css class "radio" like the following:
<span class="input-nile">
<input type="radio" value="" name="user[nile_administration]" class="input__field input__field-nile radio" id="user_nile_administration_classinput__field_input__field-nile_radio">
<label class="radio-label">Nile Administration</label>
</span>
How can i do that?
The issue is with the place of the colon
replace
<%= f.radio_button :nile_administration, class: 'input__field input__field-nile radio' %>
with
<%= f.radio_button :nile_administration , :class => 'input__field input__field-nile radio' %>
Try this:
<%= f.radio_button :nile_administration, '', '', class: 'input__field input__field-nile radio' %>
As mentioned in the docs, radio_button takes its options as the 4th argument:
radio_button(object_name, method, tag_value, options = {})
I think this is work for you:
<span class="input-nile">
<%= f.radio_button :nile_administration,"",class: 'input__field input__field-nile radio', id: 'user_nile_administration_classinput__field_input__field-nile_radio'%>
<label class="radio-label">Nile Administration</label>
</span>
You can set the custom id, classes, and other attributes for the f.radio_button as follows. Because it only takes 3 arguments. That is why using brackets.
<%= f.radio_button :entity_type, 'practice', { checked: true, id: 'entity_type_practice', class: "custom-control-input entity-radio-button" } %>

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).

Rails: Setting a value to input field if variable exists

I'm trying to set a value to two text field inputs when an id is passed to the new action in the controller. The current code works but I'm wondering if the code can be shortened.
Current code
View
<div class="custom-input">
<% if #debtor %>
<input type="text" name="debtor_name" class="form-control" id="debtor-search-form" value='<%= #debtor.name %>'>
<% else %>
<input type="text" name="debtor_name" class="form-control" id="debtor-search-form">
<% end %>
</div>
<% if #debtor %>
<%= f.text_field :debtor_id, class: "form-control", value: #debtor.id %>
<% else %>
<%= f.text_field :debtor_id, class: "form-control" %>
<% end %>
I tried removing the if-else part to make the code shorter
Shorter code
View
<div class="custom-input">
<input type="text" name="debtor_name" class="form-control" id="debtor-search-form" value='<%= #debtor.name if #debtor %>'>
</div>
<%= f.text_field :debtor_id, class: "form-control", value: #debtor.id if #debtor %>
When no debtor is passed, the shortened code results to the first input having a "hanging" value tag (i.e. it just shows value. no equal sign after it)
<input type="text" name="debtor_name" class="form-control ui-autocomplete-input" id="debtor-search-form" value autocomplete="off">
while the second input disappears.
Is a "hanging" value tag ok? I inspected the html and the "hanging" value tag resolves to value="" if i click 'edit as html'
Is there a way to shorten the code or should i just stick with it?
Having an HTML attribute as just value is fine, in HTML5. Also, the raw HTML source code probably reads as value='', judging by your html.erb code.
I guess that you're using Chrome's or Firefox's developer tools, that will try to correct and format odd looking HTML for you, and will probably display it without the empty =''.
Then, the problem with this:
<%= f.text_field :debtor_id, class: "form-control", value: #debtor.id if #debtor %>
Is operator precedence. Your if applies to the whole statement.
Try with:
<%= f.text_field :debtor_id, class: "form-control", value: (#debtor.id if #debtor) %>
Or:
<%= f.text_field :debtor_id, class: "form-control", value: #debtor.try!(:id) %>
The hanging value tag doesn't make a difference. As you saw yourself, it's the same as value="", which is the "default" value. It is also completely valid HTML5.
You can use try try object
<div class="custom-input">
<input type="text" name="debtor_name" class="form-control" id="debtor-search-form" value='<%= #debtor.try(:name) %>'>
</div>
<%= f.text_field :debtor_id, class: "form-control", value: #debtor.try(:id) %>

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

Resources