Search code examples
ruby-on-railsrubyruby-on-rails-4simple-formransack

How to display ransack checkbox in custom order


I am building a rails job app and using the ransack gem. In creating a job post, users have the ability to choose the type of job from a collection. This is the code for that

<%= f.input :role, collection: ["Fullstack Developer", "Backend 
 Developer", "Frontend Developer", "Engineer", "IOS Developer", 
 "Android Developer", "Designer", "Business Developer"], :label => 
 "Role" %>

In my job index, I display this collection with ransack. The code is below

<div class="filter-style">
  <h4>Roles</h4>
  <% new_roles = [] %>
  <%= search_form_for @search, :class => 'filters_click' do |f| %>
    <% @jobs.each do |job| %>
      <% if job.role? %>
        <% new_roles << job.role %>
      <% end %>
    <% end %>

    <% new_roles.uniq.each do |new_role| %>
      <div class="styled-input-container">
        <a>
          <label>
            <%= check_box_tag('q[role_eq_any][]', new_role) %>
              <%= new_role %>
          </label>
        </a>
      </div>
    <% end %>
  <% end %>
</div>

What i want is to display the collection in the same order as in the job new page. For example, i want to display in order of "Fullstack Developer", "Backend Developer" etc.


Solution

  • The best way I can think of right now is to do the following.

    1. First create a variable with the order you'd like the array to be in.

      <% role_order = [
        "Fullstack Developer", "Backend Developer",  "Fronten Developer",
        "Engineer",            "IOS Developer",      "Android Developer",
        "Designer",            "Business Developer"
      ] %>
      
    2. Collect the roles you are going to display.

      <% new_roles = @jobs.map(&:role).select(&:present?).uniq %>
      
    3. Order the array by using the Array#& method. This will take an intersection of the two arrays (output the items that are in both arrays). In the order that is determined by the array where you call the method on (the first array).

      <% new_roles = role_order & new_roles %>
      

    Note: If you are missing elements in your role_order array they will not be in your new_roles array after step 3. Make sure all possibilities are present in role_order. If you want some extra security that you're not missing out any elements you could raise an excepion.

    Furthermore the intersection also removes double elements. That's why I made sure that it didn't contain double elements (see step 2) before making the intersection, otherwise my example below wouldn't work (since the size is never the same if double elements are removed).

    Example raising an exception:

    <% new_roles2 = role_order & new_roles %>
    <% raise 'Missing roles in role_order array!' unless new_roles.size == new_roles2.size %>
    

    Alternatively you could make a model for the job roles and add an order attribute. Than when fetching the instances order by that attribute.

    <% new_roles = Role.where(id: @jobs.select(:role_id)).order(:order_attr) %>