Help us understand the problem. What is going on with this article?

SimpleFormのBootstrap4対応

More than 3 years have passed since last update.

足跡を残しておく。

HTMLの構造が違う

https://getbootstrap.com/docs/4.0/components/forms/#server-side
invalid-feedback などとりあえず形が違う。

config/initializers/simple_form_boosstrap.rb を編集する。自分のところでは下記のようになった。error_class の名前を is-invalid にしたり、 エラー時のspanのクラスをinvalid-feedbackにしたり。

horizontal_formがデフォルトになっていたり、:full_errorになっているのはこちらの都合なので、適宜直していただければ。

# Use this setup block to configure all options available in SimpleForm.
# @see https://suin.io/546
SimpleForm.setup do |config|
  config.error_notification_class = 'alert alert-danger'
  config.button_class = 'btn btn-default'
  config.boolean_label_class = nil

  config.wrappers :vertical_form, tag: 'div', class: 'form-group row', error_class: 'is-invalid' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :minlength
    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: 'invalid-feedback' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

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

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

  config.wrappers :vertical_boolean, tag: 'div', class: 'form-group row', error_class: 'is-invalid' 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: 'invalid-feedback' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group row', error_class: 'is-invalid' 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: 'invalid-feedback' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :horizontal_form, tag: 'div', class: 'form-group row', error_class: 'is-invalid' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :minlength
    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: 'invalid-feedback' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group row', error_class: 'is-invalid' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :minlength
    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: 'invalid-feedback' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group row', error_class: 'is-invalid' 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 :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 row', error_class: 'is-invalid' 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: 'invalid-feedback' }
      ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
    end
  end

  config.wrappers :inline_form, tag: 'div', class: 'form-group row', error_class: 'is-invalid' do |b|
    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :minlength
    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: 'invalid-feedback' }
    b.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
  end

  config.wrappers :multi_select, tag: 'div', class: 'form-group row', error_class: 'is-invalid' do |b|
    b.use :html5
    b.optional :readonly
    b.use :label, class: 'control-label col-sm-3'
    b.wrapper tag: 'div', class: 'form-inline col-sm-9' do |ba|
      ba.use :input, class: 'form-control'
      ba.use :full_error, wrap_with: { tag: 'span', class: 'invalid-feedback' }
      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 = :horizontal_form
  config.wrapper_mappings = {
    check_boxes: :horizontal_radio_and_checkboxes,
    radio_buttons: :horizontal_radio_and_checkboxes,
    file: :horizontal_file_input,
    boolean: :horizontal_boolean,
    datetime: :multi_select,
    date: :multi_select,
    time: :multi_select
  }
end

バリデーションが飾られない

上記をやるだけでは画面にフィードバックも出ないし、色分けもされない。
とりあえず、formに was-validatedを付けると表示されるようにはなるので、下記のようなヘルパーを書いた。多分SimpleFormがすぐに追随すると思う(これは無駄な努力感)。

module ApplicationHelper
  def simple_form_ex_for(record, options = {}, &block)
    classes = ['form-horizontal']
    if record.is_a?(Array)
      classes.push('was-validated') if record.last.try(:errors).present?
    else
      classes.push('was-validated') if record.try(:errors).present?
    end

    simple_form_for(record, html: {class: classes.join(' ')}, &block)
  end
end

invalidなのにグリーンの枠

form-control:validは、ブラウザ側のバリデーションのセレクタだが、これが悪さしてしまう様子。よくわからなくて、下記のようなscssを書いて逃げた。

/* for bootstrap4 validation */
form.was-validated {
  .is-invalid {
    .form-control {
      border-color: #dc3545;
    }
  }
}

おしまいに

やりたいこと出来たのだけど、教材の内容で使おうとしていたのでこれはオーバースペック。おとなしくBootstrap3にすることにした。

ms2sato
何でも屋だが、最近はRails中心。JavaScript好き。レビューやタスク分解が多くて近頃仕事ではコード書けていない。仕事でもプライベートでもコラボできる人が常に欲しい人。 会社では人を育てるの中心で https://circlearound.co.jp/training/ こんなのやってます。 独り言はこっち https://ms2sato.circlearound.co.jp
https://circlearound.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away