How to change my custom error html from rendering itself twice? - ruby-on-rails

When I try to create a category by using Ajax I get a strange behavior with my error message.
Right now I have my error message appearing like this:
My create.js.erb and new.js.erb both have the same code which is just this line:
$(".cc-form").html("<%= escape_javascript(render(:partial => 'categories/form', locals: { category: #category })) %>");
This is my category form:
<%= form_for(#category, :remote => true, :html => { :class => "add-form", :id => "cform" }) do |f| %>
<fieldset>
<p>
<%= f.label :name, "Category Name *" %>
<br />
<%= f.text_field :name %>
</p>
<div class="form-actions">
<%= f.submit "Create" %>
</div>
</fieldset>
Here is the code to enable custom error HTML:
# application.rb
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
errors = Array(instance.error_message).join(',')
%(#{html_tag}<span class="validation-error"> #{errors}</span>).html_safe
end
Then the HTML itself along with the error HTML:
<p>
<label for="category_name">Category Name *</label><span class="validation-error"> can't be blank</span>
<br>
<input id="category_name" name="category[name]" size="30" type="text" value=""><span class="validation-error"> can't be blank</span>
</p>
I only want the error message next to the label and not the right side of the input. How would I do this? The format is tricky for me when I look at it.
Thanks.

I guess you use field_error_proc badly, because it's good to wrap the input field into element with special class. Field_error_proc tags both the label and input tag with field_with_error by default since the refered object (:name that means category.name having the errors array) is the same. It's not a defect, because it's good for changing your label's color to red in this case. I checked the Rails code (actionpack/lib/action_view/helpers/tags/label.rb) and you can't turn this behavior off for labels (it can be a feature request), so I guess there's only one solution for your problem if you use plain html for labels.
I have two solutions now for your problem:
Instead of
<%= f.label :name, "Category Name *" %>
use
<label for="category_name">Category Name *</label>
in your view.
It's not too nice, but you can use f.label if you make form .label .validation-error { display: none } in your stylesheet file. I know it's just a workaround, but if f.label is necessary, then I don't know better solution.

You have two of these <span> tags in the page:
<span class="validation-error"> can't be blank</span>
EDIT:
Okay, it looks like both the label and the input need to be wrapped with a custom error. Here are a couple of links:
http://stackoverflow.com/questions/5267998/rails-3-field-with-errors-wrapper-changes-the-page-appearance-how-to-avoid-t
https://gist.github.com/1464315

Related

How do I hide the form title that appears inside a legend tag when generating check boxes for an association using simple-form?

I'm using simple-form (Ruby 2.5.1, Rails 5.2.3, simple-form 4.1.0) to generate checkboxes for an association. The form element it generates includes an overall title for the section that defaults to the name of the association (in this case, "Menu item tags") and is inside a tag. I want to hide it completely, but can't.
I can change the text to "Test" using label: "Test", but label: false doesn't hide it like I'd expect. I've read the docs and done my best to read the source, but I can't make any progress.
Here's the simple-form call:
f.association :menu_item_tags, as: :check_boxes
And here's the HTML output:
<fieldset class="form-group check_boxes optional listing_menus_menu_sections_menu_items_menu_item_tags form-group-valid">
<legend class="col-form-label pt-0">Menu item tags</legend>
<input type="hidden" name="listing[menus_attributes][0][menu_sections_attributes][0][menu_items_attributes][0][menu_item_tag_ids][]" value="">
<div class="form-check">
<input class="form-check-input is-valid check_boxes optional" type="checkbox" value="1" checked="checked" name="listing[menus_attributes][0][menu_sections_attributes][0][menu_items_attributes][0][menu_item_tag_ids][]" id="listing_menus_attributes_0_menu_sections_attributes_0_menu_items_attributes_0_menu_item_tag_ids_1">
<label class="collection_check_boxes" for="listing_menus_attributes_0_menu_sections_attributes_0_menu_items_attributes_0_menu_item_tag_ids_1">Vegetarian</label>
</div>
</fieldset>
I need to remove the tag on the second line of the HTML. label: false seems like the obvious convention, but it doesn't work.
Edit: This is not a duplicate of Remove outer label from collection_check_boxes. They're using a different function, getting different HTML out, and describing a different problem (that everything is wrapped in a label element). And the solution doesn't fix or affect the behavior I'm describing.
Edit: Here's a simplified version of the form in question, in response to a comment below:
<%= simple_form_for #listing do |f| %>
<%= f.simple_fields_for :menus do |f| %>
<%= f.simple_fields_for :menu_sections do |f| %>
<%= f.simple_fields_for :menu_items do |f| %>
<%= f.association :menu_item_tags, as: :check_boxes %>
<% end %>
<% end %>
<% end %>
<% end %>
= f.association :menu_item_tags, as: :check_boxes, legend_tag: false
You can eliminate the legend that is created by simple form with label: ""
You can do the following in css:
form[name="your_form_name"]>fieldset>legend {
display: none;
}
But it's purely cosmetic
;)
According to documentation:
label: false
should work to hide the generated <legend> element.
I tested this and found that this in fact does not work.
The workaround I found to work was:
label: ''
The <legend> element will still be generated but it will be blank.

How to add a span element to an i18n localized label in Rails 3.2.3?

I would like to add a span element to my i18n localized label in Rails 3.2.3.
This is what I've got:
<%= f.label :address, "<span class=\"optional\">optional</span>".html_safe %>
However, in the output it produces:
<label for="person_address">
<span class="optional">optional</span>
</label>
What I need is this:
<label for="person_address">
Address <span class="optional">optional</span>
</label>
Can anybody tell me how to do this?
use the block form and translate the attribute name "manually" :
<%= f.label :address do %>
<%= f.object.class.human_attribute_name :address %>
<span class="optional">optional</span>
<% end %>
note
The second parameter in the 'label' helper will be the text of the label. If you did this:
<%= f.label :address, "Address <span class=\"optional\">optional</span>".html_safe %>
It would show correctly, I think.
You an also add html to the yml file and use .html_safe on the yml item explicitly it would also work.
<%= f.label :address, t('path.to.label').html_safe %>
I'd also be tempted to try something with javascript and css - to class the field and add something via jquery or with a css :after to the label.

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

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