Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Wrapper Mappings #1751

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ the wrapper as well:
<% end %>
```

By default, **Simple Form** generates a hidden field to handle the un-checked case for boolean fields.
By default, **Simple Form** generates a hidden field to handle the un-checked case for boolean fields.
Passing `unchecked_value: false` in the options for boolean fields will cause this hidden field to be omitted,
following the convention in Rails. You can also specify `include_hidden: false` to skip the hidden field:

Expand Down Expand Up @@ -1187,6 +1187,43 @@ by passing the html5 option:
<%= f.input :expires_at, as: :date, html5: true %>
```

## Wrapper Mappings

The simplest default wrapper for all inputs is defined in the simple_form initializer.

```
config.default_wrapper = :default
```

As custom wrappers are added to your configuration it may become appropriate to map an input to a specific wrapper, a good example of this would be the config that is generated with the bootstrap install. This would override *:default* with *:bs5_boolean_collection* for those inputs only.

```
config.wrapper_mappings = {
# ..8<..
check_boxes: :bs5_boolean_collection,
radio_buttons: :bs5_boolean_collection,
# ..8<..
}
```

This may be further exhanced to have multiple sets of wrapper mappings so that you can use a set of mappings for a single form or set of fields, instead of setting the wrapper for each input.

```
config.wrapper_mappings[:tables] = {
select: :bs5_select2,
string: :bs5_input_float,
}
```

The form builder accepts a *:wrapper_mappings* option to cope with this situation.

```
simple_form_for(object, wrapper_mappings: :table) do |f|
f.input :name
end
```


### Using non Active Record objects

There are few ways to build forms with objects that don't inherit from Active Record, as
Expand Down
16 changes: 13 additions & 3 deletions lib/simple_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,21 @@ def self.configured? #:nodoc:

# Custom wrappers for input types. This should be a hash containing an input
# type as key and the wrapper that will be used for all inputs with specified type.
# e.g { string: :string_wrapper, boolean: :boolean_wrapper }
# e.g config.wrapper_mappings = { string: :string_wrapper, boolean: :boolean_wrapper }
# You can also set a wrapper mapping per form basis.
# e.g simple_form_for(@foo, wrapper_mappings: { check_boxes: :bootstrap_checkbox })
mattr_accessor :wrapper_mappings
@@wrapper_mappings = nil
# If you wish to create another set of wrappers you can do so
# config.wrapper_mappings[:inline] = { string: :inline_string }
# Which will allow referencing a set of wrappers with the set key
# e.g simple_form_for(@foo, wrapper_mappings: :custom)

def self.wrapper_mappings
@@wrapper_mappings ||= {}
end

def self.wrapper_mappings=(opts)
wrapper_mappings[:default] = opts
end

# Namespaces where SimpleForm should look for custom input classes that override
# default inputs. Namespaces are given as string to allow lazy loading inputs.
Expand Down
9 changes: 4 additions & 5 deletions lib/simple_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -636,11 +636,10 @@ def find_mapping(input_type)
# 1) It tries to find a wrapper for the current form
# 2) If not, it tries to find a config
def find_wrapper_mapping(input_type)
if options[:wrapper_mappings] && options[:wrapper_mappings][input_type]
options[:wrapper_mappings][input_type]
else
SimpleForm.wrapper_mappings && SimpleForm.wrapper_mappings[input_type]
end
mapping = options[:wrapper_mappings]
mapping.is_a?(Hash) && mapping[input_type] ||
SimpleForm.wrapper_mappings.fetch(mapping, {}).try(:[], input_type) ||
SimpleForm.wrapper_mappings.fetch(:default, {}).try(:[], input_type)
end

def find_wrapper(input_type, options)
Expand Down
17 changes: 17 additions & 0 deletions test/form_builder/wrapper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,23 @@ class WrapperTest < ActionView::TestCase
end
end

test 'uses custom wrapper mapping for specified in config mapping' do
swap_wrapper :another do
swap SimpleForm, wrapper_mappings: { string: :not_found } do
begin
SimpleForm.wrapper_mappings[:custom] = { string: :another }
with_concat_form_for @user, wrapper_mappings: :custom do |f|
concat f.input :name
end
assert_select "section.custom_wrapper div.another_wrapper label"
assert_select "section.custom_wrapper div.another_wrapper input.string"
ensure
SimpleForm.wrapper_mappings.delete(:custom)
end
end
end
end

test 'uses custom wrapper mapping per form basis' do
swap_wrapper :another do
with_concat_form_for @user, wrapper_mappings: { string: :another } do |f|
Expand Down