Сортировка таблицы по атрибуту вложенных моделей в 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.