0

I have the hash, below:

library = {"1"=>{"title"=>"bbb", "money"=>10}, "2"=>{"title"=>"aaa", "money"=>12}}

and my application_helper.rb:

  def sortable_columns
    %w[title money]
  end

  def sort_column
    sortable_columns.include?(params[:column]) ? params[:column] : "title"
  end

  def sort_direction
    %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
  end

  def sort_link(column, title)
    direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
    icon = sort_direction == "asc" ? "fa fa-arrow-down" : "fa fa-arrow-up"
    icon = column == sort_column ? icon : ""
    link_to "#{title} <i class='#{icon}'></i>".html_safe, {column: column, direction: direction}
  end

My table in table.html.erb:

          <table class="table table-striped">
            <thead>
            <tr>
                <th>#</th>
                <% sortable_columns.each do |column| %>
                  <th><%= sort_link column, column %></th>
                <% end %>
            </tr>
            </thead>
            <tbody>
              <% library.sort_by {|k| k[1][sort_column]}.each_with_index do |data, i| %>
               ...

              <% end %>
            </tbody>
          </table>

and now - after click in "title" or "money" header - table's sorting ASC. I would like it to display DESC when clicked again (with icon arrow-down). How can this be done? I thought about "reverse", after library.sort_by {|k| k[1][sort_column]}, but doesn't work.

  • Since the whole library is rendered client-side – have you considered using one of the various JavaScript table sorting solutions out there? – Stefan May 21 '19 at 06:22
  • Nope, I haven't considered. Do you have an idea? – Kamil Pikula May 21 '19 at 06:25
  • [tablesorter](https://mottie.github.io/tablesorter/docs/index.html) maybe? You could also write your own, see [Sorting HTML table with JavaScript](https://stackoverflow.com/questions/14267781/sorting-html-table-with-javascript) – Stefan May 21 '19 at 06:33
  • BTW, why did you put the data into a hash rather than a database table? Wouldn't it make more sense to use ActiveRecord, given that this is a Rails question? – Stefan May 21 '19 at 06:36
  • @Stefan because I'm getting the data from the api in json and I don't need to keep them on the database. Your way works, but I used `tap` method in Ruby. Thanks. :) – Kamil Pikula May 22 '19 at 06:58

2 Answers2

0

Reverse does work:

library = {"1"=>{"title"=>"bbb", "money"=>10}, "2"=>{"title"=>"aaa", "money"=>12}}

sort_column = "money"

sort_direction = "asc"
library
  .sort_by {|k| k[1][sort_column]}
  .tap { |l| l.reverse! if sort_direction == "desc" }
# => [["1", {"title"=>"bbb", "money"=>10}], ["2", {"title"=>"aaa", "money"=>12}]]

sort_direction = "desc"
library
  .sort_by {|k| k[1][sort_column]}
  .tap { |l| l.reverse! if sort_direction == "desc" }
# => [["2", {"title"=>"aaa", "money"=>12}], ["1", {"title"=>"bbb", "money"=>10}]]
fphilipe
  • 9,739
  • 1
  • 40
  • 52
  • Unfortunately - no, `library` isn't an AR relation, its `ActiveSupport::HashWithIndifferentAccess` – Kamil Pikula May 21 '19 at 06:15
  • @KamilPikula what are the keys and values? Are you saying it's an array of `ActiveSupport::HashWithIndifferentAccess` where each element is sort of a row and the column you want to sort by is a key in each hash? – fphilipe May 21 '19 at 06:23
  • @KamilPikula, sorry, missed that you had `library` in your question. Updated my answer accordingly. – fphilipe May 21 '19 at 06:34
  • Damn it, I totally forgot about `tap` method in Ruby. It's works, thank you very much @fphilipe! – Kamil Pikula May 22 '19 at 06:41
0

you can sory hash as per below

if sort by only title then

library.values.sort_by{|h| h["title"] }

or you want to sort by first title and second money then use

library.values.sort_by{|h| [h["title"], h["money"]] }