Mel
Mel

Reputation: 2715

Rails - Simple Form Bootstrap - show full text of error inline - (or anywhere)

I am struggling to figure out how to use simple form with rails 5 so that I can show full error messages in my forms. All I get is a box at the top with a message that says:

Please review the problems below:  

Instead of a list of problems or any highlighted form fields - i don't get anything.

I have followed the advice in this post and replaced all references to error in my initialiser with 'full_error', but that only solves the problem for the parent form - nested fields still just get an incomplete error message. Does anyone know how to identify errors in simple form?

# Use this setup block to configure all options available in SimpleForm.
SimpleForm.setup do |config|
  config.error_notification_class = 'alert alert-danger'
  config.button_class = 'btn btn-green'
  config.boolean_label_class = nil

  config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :pattern
    b.optional :min_max
    b.optional :readonly
    b.use :label, class: 'control-label'

    b.use :input, class: 'form-control'
    b.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :readonly
    b.use :label, class: 'control-label'

    b.use :input
    b.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.optional :readonly

    b.wrapper tag: 'div', class: 'checkbox' do |ba|
      ba.use :label_input
    end

    b.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.optional :readonly
    b.use :label, class: 'control-label'
    b.use :input
    b.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :pattern
    b.optional :min_max
    b.optional :readonly
    b.use :label, class: 'col-sm-3 control-label'

    b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
      ba.use :input, class: 'form-control'
      ba.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :readonly
    b.use :label, class: 'col-sm-3 control-label'

    b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
      ba.use :input
      ba.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.optional :readonly

    b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr|
      wr.wrapper tag: 'div', class: 'checkbox' do |ba|
        ba.use :label_input
      end

      wr.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
      wr.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.optional :readonly

    b.use :label, class: 'col-sm-3 control-label'

    b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
      ba.use :input
      ba.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :pattern
    b.optional :min_max
    b.optional :readonly
    b.use :label, class: 'sr-only'

    b.use :input, class: 'form-control'
    b.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
    b.use :html5
    b.optional :readonly
    b.use :label, class: 'control-label'
    b.wrapper tag: 'div', class: 'form-inline' do |ba|
      ba.use :input, class: 'form-control'
      ba.use :full_error, wrap_with: { tag: 'span', class: 'help-block' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end
  # Wrappers for forms and inputs using the Bootstrap toolkit.
  # Check the Bootstrap docs (http://getbootstrap.com)
  # to learn about the different styles for forms and inputs,
  # buttons and other elements.
  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

FORM

<%= simple_form_for(@proposal) do |f| %>
  <%= f.error_notification %>

 <% @proposal.errors.full_messages.each do |msg| %>
    <%= li= msg %>
 <% end %>



  <div class="form-inputs" style="margin-bottom: 50px">
  <!--   General Organisation details -->
    <div class="row">
      <div class="col-md-12">
        <%= f.input :title, :label => "Title" %>

      </div>
    </div>
    <div class="row">
      <div class="col-md-12">
        <%= f.input :byline, :label => "Tagline" %>
      </div>
    </div>

    <div class="row">
      <div class="col-md-12">
        <%= f.input :description, as: :text, :label => "Outline your proposal", input_html: { rows: 15 } %>
      </div>
    </div>




  <!--   Package: :ethics considerations -->
  <div class="row">
    <div class="col-md-12">
      <div class="form_title">Research Ethics</div>
    </div>
  </div>

  <div class="row">
    <div class="col-md-12">

    <%= f.simple_fields_for :ethics do |f| %>
      <%= f.error_notification %>
        <%= render 'package/ethics/ethics_fields', f: f %>

    <% end %>

    <%= link_to_add_association 'Add another ethics issue', f, :ethics, partial: 'package/ethics/ethics_fields' %>
    </div>
  </div>


  </div>

  <div class="row">
    <div class="col-md-10 col-md-offset-1" style="margin-top: 50px">
      <div class="form-actions">
        <%= f.button :submit %>
      </div>
    </div>
  </div>
<% end %>

NESTED FIELDS

<div class="nested-fields">

    <%# @proposal.ethics.errors.full_messages.each do |e| %>
        <li><%#=  e  %></li>
    <%# end %>
    <div class="form-inputs">
      <div class="row">
          <div class="col-md-12 ">
          <%= f.select :category, [ "Risk of harm", "Informed consent", "Anonymity and Confidentiality", "Deceptive practices", "Right to withdraw"], { label: "Principle" }, id: "main_category" %>
          <%= f.select :subcategory, [], {}, id: "sub_category", disabled: true %>
          <%= f.input :consideration, as: :text, :label => "Identify the ethics considerations?",  :input_html => {:rows => 8} %>
          <%= f.input :plan, as: :text, :label => "How will these considerations be managed?",  :input_html => {:rows => 8} %>
        </div>
      </div>
  </div>
  <div class="row">
      <div class="col-md-6" style="margin-top: 20px; margin-bottom: 50px">
        <%= link_to_remove_association 'Remove this ethical issue', f %>
      </div>

  </div>
</div>

Upvotes: 3

Views: 3126

Answers (4)

OuttaSpaceTime
OuttaSpaceTime

Reputation: 986

to get it working inline with simple form by default you have to use bootstrap_simple-form and make sure everything within controller is set up correctly.

For reference check the answers given here by me and Hollownest

Showing fields with errors for nested forms in Rails 3.2 + SimpleForm

Upvotes: 0

Ben Trewern
Ben Trewern

Reputation: 1740

It looks like you are getting haml and erb mixed up in your error displaying code.

This:

 <% @proposal.errors.full_messages.each do |msg| %>
   <%= li= msg %>
 <% end %>

should look more like this:

<% if @proposal.errors.any? %>
<ul>
  <% @proposal.errors.full_messages.each do |msg| %>
    <li><%= msg %></li>
  <% end %>
</ul>
<% end %>

I'm guessing you are using Cocoon so you'll need to set that up correctly but there is a gotcha when using Rails 5.

You'll need something like the following in your models:

class Proposal < ApplicationRecord
  has_many: :ethics, inverse_of: :proposal
  accepts_nested_attributes_for :ethics ...
...

and

class Ethic < ApplicationRecord
  belongs_to :proposal, inverse_of: :ethics
...

note the has_many .. inverse_of clause which works round a bug in Rails 5.

If you setup the accepts_nested_attributes_for clause correctly I think @proposal.errors should contain all the errors for the form.

Upvotes: 1

KcUS_unico
KcUS_unico

Reputation: 513

Another option could be to display the error messages directly at the field.

<%= f.input :title, :label => "Title", id:"title" %>
<%= f.error :title, :id => "title_error" %>

This will show the error message for title next to the title field. You can add an f.error method to each field in your form instead of displaying a <ul> above the form, or together with a <ul> above your form.

For nested_form_fields try to add validates_associated :assoc_model_name into the main model. This will run validations for the associated model as well.

Upvotes: 0

Sravan
Sravan

Reputation: 18657

The first mistake I found in your code is, in your nested field you have taken the same variable f in the parameter, which may get consfused with the parent parameenter code hereter f

So,

nested will be,

<%= f.simple_fields_for :ethics do |ff| %>
      <%= ff.error_notification %>
      <%= render 'package/ethics/ethics_fields', f: f %>
<% end %>

Now the form,

<%= simple_form_for(@proposal) do |f| %>
  <%= f.error_notification %>

 <% @proposal.errors.full_messages.each do |msg| %>
    <%= li= msg %>
 <% end %>



  <div class="form-inputs" style="margin-bottom: 50px">
  <!--   General Organisation details -->
    <div class="row">
      <div class="col-md-12">
        <%= f.input :title, :label => "Title" %>

      </div>
    </div>
    <div class="row">
      <div class="col-md-12">
        <%= f.input :byline, :label => "Tagline" %>
      </div>
    </div>

    <div class="row">
      <div class="col-md-12">
        <%= f.input :description, as: :text, :label => "Outline your proposal", input_html: { rows: 15 } %>
      </div>
    </div>




  <!--   Package: :ethics considerations -->
  <div class="row">
    <div class="col-md-12">
      <div class="form_title">Research Ethics</div>
    </div>
  </div>

  <div class="row">
    <div class="col-md-12">

    <%= f.simple_fields_for :ethics do |ff| %>
      <%= ff.error_notification %>
        <%= render 'package/ethics/ethics_fields', f: ff %>

    <% end %>

    <%= link_to_add_association 'Add another ethics issue', f, :ethics, partial: 'package/ethics/ethics_fields' %>
    </div>
  </div>


  </div>

  <div class="row">
    <div class="col-md-10 col-md-offset-1" style="margin-top: 50px">
      <div class="form-actions">
        <%= f.button :submit %>
      </div>
    </div>
  </div>
<% end %>




<%= f.simple_fields_for :ethics do |ff| %>
    <%= ff.error_notification %>
    <%= render 'package/ethics/ethics_fields', f: ff %>
    <% @proposal.ethics.errors.full_messages.each do |msg| %>
        <%= li= msg %>
    <% end %>
<% end %>

Edit: Even if the above does not solve the issue,

Try getting the errors from the ethics object from the @proposal variable

So,

<%= f.simple_fields_for :ethics do |ff| %>
    <%= ff.error_notification %>
    <% @proposal.ethics.errors.full_messages.each do |msg| %>
    <%= li= msg %>
    <% end %>
    <%= render 'package/ethics/ethics_fields', f: f %>
<% end %>

Upvotes: 0

Related Questions