Skip to content

Instantly share code, notes, and snippets.

@kasparsj
Last active February 27, 2017 23:13
Show Gist options
  • Save kasparsj/ab0de878e24c4a0eb08d1673aff18e91 to your computer and use it in GitHub Desktop.
Save kasparsj/ab0de878e24c4a0eb08d1673aff18e91 to your computer and use it in GitHub Desktop.
Patch for ActionView::Helpers to add 'include_selected' option to CollectionSelect, options_from_collection_for_select, options_for_select
module ActionView::Helpers
module Tags
class CollectionSelect < Base
def render
option_tags_options = {
:selected => @options.fetch(:selected) { value(@object) },
:include_selected => @options.fetch(:include_selected, false),
:disabled => @options[:disabled]
}
select_content_tag(
options_from_collection_for_select(@collection, @value_method, @text_method, option_tags_options),
@options, @html_options
)
end
end
end
module FormOptionsHelper
def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
options = collection.map do |element|
[value_for_collection(element, text_method), value_for_collection(element, value_method), option_html_attributes(element)]
end
selected, disabled, include_selected = extract_selected_and_disabled(selected)
select_deselect = {
selected: extract_values_from_collection(collection, value_method, selected),
disabled: extract_values_from_collection(collection, value_method, disabled),
include_selected: include_selected
}
options_for_select(options, select_deselect)
end
def options_for_select(container, selected = nil)
return container if String === container
selected, disabled, include_selected = extract_selected_and_disabled(selected)
selected, disabled = [selected, disabled].map do |r|
Array(r).map { |item| item.to_s }
end
if include_selected
include = selected.select{|s| container.find{|element| option_text_and_value(element).last == s}.nil?}
unless include.empty?
container = [selected] + container
end
end
# Rails 4 version
container.map do |element|
html_attributes = option_html_attributes(element)
text, value = option_text_and_value(element).map(&:to_s)
html_attributes[:selected] ||= option_value_selected?(value, selected)
html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled)
html_attributes[:value] = value
content_tag_string(:option, text, html_attributes)
end.join("\n").html_safe
end
def extract_selected_and_disabled(selected)
if selected.is_a?(Proc)
[selected, nil, nil]
else
selected = Array.wrap(selected)
options = selected.extract_options!.symbolize_keys
selected_items = options.fetch(:selected, selected)
[selected_items, options[:disabled], options[:include_selected]]
end
end
end
end
@kasparsj
Copy link
Author

kasparsj commented Feb 27, 2017

Rails include_selected

A handy patch for when you want to force-use a select box and not loose any pre-existing/legacy data.

Examples:

language select, with a deprecated language

options_for_select([["English", "en"], ["German", "de"]], {selected: "Russian", include_selected: true})

will result in:

<option value="Russian" selected="selected">Russian<option>
<option value="en">English<option>
<option value="de">German<option>

language select with multiple values

options_for_select([["English", "en"], ["German", "de"]], {selected: ["Russian", "German"], include_selected: true})

will result in:

<option value="Russian" selected="selected">Russian<option>
<option value="en">English<option>
<option value="de" selected="selected">German<option>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment