Skip to content

Instantly share code, notes, and snippets.

@gomo
Last active March 14, 2018 08:48
Show Gist options
  • Save gomo/81a9ce8f9a31d3be7d56519e57b57426 to your computer and use it in GitHub Desktop.
Save gomo/81a9ce8f9a31d3be7d56519e57b57426 to your computer and use it in GitHub Desktop.
The utility for grouped_collection_select of rails.
class Grouper
class GroupItem
attr_reader :label, :children
def initialize(label, children)
@label = label
@children = children
end
end
def initialize(group_list, children, &block)
@others_label = group_list.pop
@group_list = group_list
@children = children
@children_selector = block
end
def map
rest_list = @children
res = @group_list.map do |group|
selected_list, rest_list = rest_list.partition {|item| @children_selector.call(group, item) }
next if selected_list.nil? || selected_list.blank?
yield GroupItem.new(group, selected_list)
end
res << yield(GroupItem.new(@others_label, rest_list)) if @others_label && rest_list.any?
res
end
end

In your controller.

users = [
  [1, "Rollam Westerling"],
  [2, "Jeffory Mallister"],
  [3, "Rhaenys Targaryen"],
  [4, "Ulrick Dayne"],
  [5, "Missandei"],
  [6, "Areo Hotah"],
  [7, "Alyx Frey"],
  [8, "Hunnimore"],
  [9, "Mycah"],
  [10, "Plummer"],
  [11, "Willas Tyrell"],
  [12, "Alester Florent"],
  [13, "Pycelle"],
  [14, "Tickler"],
  [15, "Steffon Baratheon"],
  [16, "Aemon Rivers"],
  [17, "Franklyn Frey"],
  [18, "Sylwa Paege"],
  [19, "Rhaego"],
  [20, "Addison Hill"]
]

# Please return boolean in the block passed to the constructor.
@groups = Grouper.new(('A'..'Z').to_a.push('Other'), users) {|letter, user| user.last.start_with?(letter) }

In your view

<%= form_with path: '/' do |f|%>
  <%= f.grouped_collection_select :user_id, @groups, :children, :label, :first, :last, include_blank: 'Select User' %>
<%end%>

Result HTML

<select name="user_id">
  <option value="">Select User</option>
  <optgroup label="A">
    <option value="6">Areo Hotah</option>
    <option value="7">Alyx Frey</option>
    <option value="12">Alester Florent</option>
    <option value="16">Aemon Rivers</option>
    <option value="20">Addison Hill</option>
  </optgroup>
  <optgroup label="F">
    <option value="17">Franklyn Frey</option>
  </optgroup>
  <optgroup label="H">
    <option value="8">Hunnimore</option>
  </optgroup>
  <optgroup label="J">
    <option value="2">Jeffory Mallister</option>
  </optgroup>
  <optgroup label="M">
    <option value="5">Missandei</option>
    <option value="9">Mycah</option>
  </optgroup>
  <optgroup label="P">
    <option value="10">Plummer</option>
    <option value="13">Pycelle</option>
  </optgroup>
  <optgroup label="R">
    <option value="1">Rollam Westerling</option>
    <option value="3">Rhaenys Targaryen</option>
    <option value="19">Rhaego</option>
  </optgroup>
  <optgroup label="S">
    <option value="15">Steffon Baratheon</option>
    <option value="18">Sylwa Paege</option>
  </optgroup>
  <optgroup label="T">
    <option value="14">Tickler</option>
  </optgroup>
  <optgroup label="U">
    <option value="4">Ulrick Dayne</option>
  </optgroup>
  <optgroup label="W">
    <option value="11">Willas Tyrell</option>
  </optgroup>
</select>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment