Search code examples
ruby-on-railssimple-form

Dry up custom wrappers in simple_form


Rather than having almost two similar custom wrapper definition, is it possible to dry them up? for e.g:

config.wrappers :inline_checkbox, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b|
    b.use :html5
    b.wrapper :tag => 'div', :class => 'controls' do |ba|
      ba.use :label_input, :wrap_with => { :class => 'checkbox inline' }
      ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }          
    end
  end

and

config.wrappers :inline_checkbox_two, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b|
    b.use :hint,  :wrap_with => { :tag => 'p', :class => 'help-block' }
    # everything else should use the same definition as the above
  end

Solution

  • Use a module to DRY it out:

    module WrapperHelper
    
      # options:
      #   - wrapper [Hash]
      #   - label_input [Hash]
      #   - error [Hash]
      #   - use [Array] an array of arguments to pass to b.use
      def self.inline_checkbox(b, **kwargs)
        if kwargs[:use]
          b.use *kwargs[:use]
        else
          b.use :html5
        end
        wrapper_opts = {
          tag: 'div',
          class: 'control-group'
          error_class: 'error'
        }.merge(kwargs[:wrapper] || {}) # merge defaults with passed `wrapper` keyword argument
        b.wrapper(wrapper_opts) do |ba|
          ba.use :label_input, 
            { wrap_with: { class: 'checkbox inline' } }.merge(kwargs[:label_input] || {})
          ba.use :error, 
            { wrap_with: { tag: 'span', class: 'help-inline' } }.merge(kwargs[:error] || {})
        end
      end
    end
    

    config.wrappers :html5_inline_checkbox do |b|
      WrapperHelper.inline_checkbox(b)
    end
    
    config.wrappers :inline_checkbox_with_helper do |b|
      WrapperHelper.inline_checkbox(b, use: [:hint, {wrap_with: { tag: 'p', class: 'help-block' }}])
    end