Сортировка таблицы по атрибуту вложенных моделей в Rail с Turbo Frames

Я создаю таблицу сотрудников, и я хотел бы отсортировать по full_rate_pence, который является атрибутом HourlyRate. У каждого сотрудника есть_много часовых_ставок, которые формируют историю увеличения или уменьшения заработной платы. Проблема заключается в попытке получить доступ к вложенной HourlyRate, потому что HourlyRate, к которому мне нужно получить доступ, находится в коллекции. Невозможно использовать .find или .find_by из-за использования :includes

Первоначально я получил следующую ошибку:

Опасный метод запроса (метод, аргументы которого используются как необработанный SQL), вызываемый с аргументом (аргументами) без атрибутов: «hourly_rates.first.full_rate_pence asc». Этот метод не следует вызывать с предоставленными пользователем значениями, такими как параметры запроса или модель. атрибуты. Известные безопасные значения можно передать, обернув их в Arel.sql().

Затем, обернув часть с помощью Arel.sql(), я получил следующую ошибку:

SQLite3::SQLException: нет такого столбца: hourly_rates.full

Модели

      class Employee < ApplicationRecord
    has_many :hourly_rates
    accepts_nested_attributes_for :hourly_rates
end
      class HourlyRate < ApplicationRecord
    belongs_to :employee
    monetize :full_rate_pence, as: 'full'
end

Ссылка в таблице

      <th scope="col">
  <%= sort_link(column: "hourly_rates.first.full", label: "Hourly Rate") %>
</th>

Вспомогательный метод для создания ссылки

      def sort_link(column:, label:)
      if column == params[:column]
        link_to(label, list_employees_path(column: column, direction: next_direction))
      else
        link_to(label, list_employees_path(column: column, direction: 'asc'))
      end
    end

Метод контроллера

      def list
  employees = Employee
      .includes(:hourly_rates)
      .where(hourly_rates: {active:true})
      .order(Arel.sql("#{params[:column]}"))
    render(partial: 'employees', locals: { employees: employees })
end

Спасибо за любой совет, как я могу реализовать это.

Дэн

1 ответ

Руби ответ:

что-то вроде:

      def list
  employees = Employee
      .includes(:hourly_rates)
      .where(hourly_rates: {active:true})

  # you can add to the query before the end:
  case params[:column]
  when "Hourly Rate"
    employees = employees.order(hourly_rates.first.full)
  else
    employees = employees.order(id)
  end

  render(partial: 'employees', locals: { employees: employees })
end

Сортировка Javascript:

      var asc = 0;
function sort_table(table, col) {
    $('.sortorder').remove();
    if (asc == 2) { asc = -1; } else { asc = 2; }
    var rows = table.tBodies[0].rows;
    var rlen = rows.length;
    if (!table.tHead) { rlen--; }
    var arr = new Array();
    var i, j, cells, clen;
    // fill the array with values from the table
    // does not like empty rows, so check your haml!
    for (i = 0; i < rlen; i++) {
        cells = rows[i].cells;
        clen = cells.length;
        arr[i] = new Array();
        for (j = 0; j < clen; j++) { arr[i][j] = cells[j].innerHTML; }
    }
    // sort the array by the specified column number (col) and order (asc)
    arr.sort(function (a, b) {
        var retval = 0;
        var col1 = a[col].toLowerCase().replace(',', '').replace('$', '').replace(' usd', '')
        var col2 = b[col].toLowerCase().replace(',', '').replace('$', '').replace(' usd', '')
        var fA = parseFloat(col1);
        var fB = parseFloat(col2);
        if (col1 != col2) {
            if ((fA == col1) && (fB == col2)) { retval = (fA > fB) ? asc : -1 * asc; } //numerical
            else { retval = (col1 > col2) ? asc : -1 * asc; }
        }
        return retval;
    });
    for (var rowidx = 0; rowidx < rlen; rowidx++) {
        for (var colidx = 0; colidx < arr[rowidx].length; colidx++) { table.tBodies[0].rows[rowidx].cells[colidx].innerHTML = arr[rowidx][colidx]; }
    }

    hdr = table.rows[0].cells[col];
    if (hdr.children.length == 0) {
        obj = hdr
    } else {
        obj = hdr.children[0]
    }
    if (asc == -1) {
        // $(hdr).html($(hdr).html() + '<span class="sortorder">▲</span>');
        $(obj).html($(obj).html() + '<span class="sortorder">▲</span>');
    } else {
        //$(hdr).html($(hdr).html() + '<span class="sortorder">▼</span>');
        $(obj).html($(obj).html() + '<span class="sortorder">▼</span>');
    }
}

вызов из представления:

      :javascript
  function sortTable(n) {
  sort_table(document.getElementById("indextable"), n);
  }
%table#indextable
  %thead
    %tr
      %th{ onclick: 'sortTable(0)' } Name
      %th{ onclick: 'sortTable(1)' } Machine
      %th{ onclick: 'sortTable(2)' } Method
      %th{ onclick: 'sortTable(3)' } Bands
  %tbody
    // etc.
Другие вопросы по тегам