Skip to content

Instantly share code, notes, and snippets.

@trevmex
Created July 7, 2010 17:11
Show Gist options
  • Select an option

  • Save trevmex/466964 to your computer and use it in GitHub Desktop.

Select an option

Save trevmex/466964 to your computer and use it in GitHub Desktop.
# options_for_select_tag: Create an options string for the Rails select_tag method.
# This is a wrapper for Rails' options_for_select method.
# The options are the same as the Rails select method, but this allows us to use it with the select_tag method.
#
# @param {String[]} container An array of strings representing the list of options.
# @param {String|String[]|Hash} selected_or_options A single value or an array of values that will be selected options in the final output, or a hash of options as follows:<br />
# - :selected - can be a single value or an array of values that will be selected options in the final output.
# - :include_blank - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.<br />
# - :prompt - set to true or a prompt string. When the select element doesn‘t have a value yet, this prepends an option with a generic prompt — "Please select" — or the given prompt string.<br />
# - :disabled - can be a single value or an array of values that will be disabled options in the final output.
def options_for_select_tag(container, selected_or_options = nil)
prompt = ''
if selected_or_options.present?
options = selected_or_options
if options.class == Hash
# Add the blank or prompt options if they are present
if options[:include_blank].present? # :include_blank and :prompt are mutually exclusive
if options[:include_blank].class == String
prompt = "<option value=\"\">#{options[:include_blank]}</option>\n"
else
prompt = "<option value=\"\"></option>\n"
end
elsif options[:prompt].present? # :include_blank and :prompt are mutually exclusive
if options[:prompt].class == String
prompt = "<option value=\"\">#{options[:prompt]}</option>\n"
else
prompt = "<option value=\"\">Please select</option>\n"
end
end
selected = {}
if options[:selected].present?
selected.merge!(:selected => options[:selected])
end
if options[:disabled].present?
selected.merge!(:disabled => options[:disabled])
end
elsif options.class == String || options.class == Array
selected = selected_or_options
else # Error State
raise ArgumentError, "'selected_or_options' parameter must be a String, Array of Strings, or a Hash of options.\n#{options.class} is invalid."
end
else # selected_or_options.blank?
selected = nil
end
# Call Rails' options_for_select method with the proper arguments and prepent the prompt
prompt + options_for_select(container, selected)
end
# options_from_csv: Create an options string for a select tag from a comma-separated file.
# This is a wrapper for Rails' options_for_select method.
# The options are the same as the Rails select method, but this allows us to use it with the select_tag method
#
# @param {String} csv A string containing comma-separated values.
# @param {String|String[]|Hash} selected_or_options A single value or an array of values that will be selected options in the final output, or a hash of options as follows:<br />
# - :split_on - the character to split the string on (default is ',').
# - :selected - can be a single value or an array of values that will be selected options in the final output.
# - :include_blank - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.<br />
# - :prompt - set to true or a prompt string. When the select element doesn‘t have a value yet, this prepends an option with a generic prompt — "Please select" — or the given prompt string.<br />
# - :disabled - can be a single value or an array of values that will be disabled options in the final output.
def options_from_csv(csv, selected_or_options = nil)
split_on = ','
if selected_or_options.class == Hash && selected_or_options[:split_on].present?
split_on = selected_or_options[:split_on]
end
container = csv.split(split_on).collect { |item| item.strip }
options_for_select_tag(container, selected_or_options)
end
describe "options_from_csv" do
it "returns options" do
helper.options_from_csv('US, Canada, UK').should == "<option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options using an alternative separator" do
helper.options_from_csv('US: Canada: UK', :split_on => ':').should == "<option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with one selected" do
helper.options_from_csv('US, Canada, UK', 'US').should == "<option value=\"US\" selected=\"selected\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with one disabled" do
helper.options_from_csv('US, Canada, UK', :disabled => 'US').should == "<option value=\"US\" disabled=\"disabled\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with one selected and one disabled" do
helper.options_from_csv('US, Canada, UK', :selected => 'Canada', :disabled => 'US').should == "<option value=\"US\" disabled=\"disabled\">US</option>\n<option value=\"Canada\" selected=\"selected\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with one selected and two disabled" do
helper.options_from_csv('US, Canada, UK', :selected => 'Canada', :disabled => ['US', 'UK']).should == "<option value=\"US\" disabled=\"disabled\">US</option>\n<option value=\"Canada\" selected=\"selected\">Canada</option>\n<option value=\"UK\" disabled=\"disabled\">UK</option>"
end
it "returns options with two selected and one disabled" do
helper.options_from_csv('US, Canada, UK', :disabled => 'Canada', :selected => ['US', 'UK']).should == "<option value=\"US\" selected=\"selected\">US</option>\n<option value=\"Canada\" disabled=\"disabled\">Canada</option>\n<option value=\"UK\" selected=\"selected\">UK</option>"
end
it "returns options with two disabled" do
helper.options_from_csv('US, Canada, UK', :disabled => ['US', 'Canada']).should == "<option value=\"US\" disabled=\"disabled\">US</option>\n<option value=\"Canada\" disabled=\"disabled\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with two selected" do
helper.options_from_csv('US, Canada, UK', ['US', 'Canada']).should == "<option value=\"US\" selected=\"selected\">US</option>\n<option value=\"Canada\" selected=\"selected\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with a blank included" do
helper.options_from_csv('US, Canada, UK', :include_blank => true).should == "<option value=\"\"></option>\n<option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with a prompt string (using include_blank)" do
helper.options_from_csv('US, Canada, UK', :include_blank => 'None').should == "<option value=\"\">None</option>\n<option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with a default prompt" do
helper.options_from_csv('US, Canada, UK', :prompt => true).should == "<option value=\"\">Please select</option>\n<option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
it "returns options with a prompt string (using prompt)" do
helper.options_from_csv('US, Canada, UK', :prompt => 'Select Country').should == "<option value=\"\">Select Country</option>\n<option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option>\n<option value=\"UK\">UK</option>"
end
end
@trevmex
Copy link
Author

trevmex commented Jul 11, 2012

Lines #18-#41 in options_for_select_tag could be refactored to another method called something like "process_options_hash" for ease of reading.

Lines #19-24 and #25-31 look VERY similar. It might be worthwhile to refactor them into a simple function that takes a string and a default string like "set_prompt(str, default)." That might make the code a bit cleaner.

Lines #33-#41 could be refactored into a method called something like "set_selected(selected, disabled)."

Line #42 "options.class == String || options.class == Array" should be changed to a method called "default_selected_option(option)." That makes it clear that a String or Array is what the Rails method expects, and is passed through. We could also inverse the check with the hash check, since that is a quicker thing to resolve, and would make the code easier to read.

None of these changes should effect the the way the tests execute.

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