Rails - передать коллекцию объекту ActiveModel

Я использую рельсы для создания таблицы данных, которая разбивается на страницы с помощью Ajax, и для этого я использую Railscast #340.

Этот эпизод использует обычный класс ActiveModel, называемый ProductsDatatable или в моем случае OrdersDatatable создать и настроить таблицу. Мой вопрос касается синтаксиса ruby ​​в этом классе. Я пытаюсь передать коллекцию заказов OrdersDatatable объект, от контроллера. Я хочу получить доступ к этой коллекции в fetch_orders метод.

Я создаю объект таблицы следующим образом в order.rb:

@datatable = OrdersDatatable.new(view_context)
@datatable.shop_id = @current_shop.id
@datatable.orders_list = @orders # which is Order.in_process

И мой OrdersDatatable класс выглядит так: (важными частями, которые, вероятно, нужно изменить, является вторая строка initialize и первая строка в fetch_orders)

class OrdersDatatable
  include Rails.application.routes.url_helpers
  include ActionView::Helpers::DateHelper
  include ActionView::Helpers::TagHelper

  delegate :params, :h, :link_to, :number_to_currency, to: :@view

  attr_accessor :shop_id, :orders_list

  def initialize(view)
    @view = view
    @orders_list = self.orders_list
  end

  def current_shop
    Shop.find(shop_id)
  end

  def as_json(options = {})
    {
      sEcho: params[:sEcho].to_i,
      iTotalRecords: orders.count,
      iTotalDisplayRecords: orders.count,
      aaData: data
    }
  end

private


  def data
    orders.map do |order|
      [
        order.id,
        order.name,
        h(time_tag(order.date_placed.in_time_zone)),
        order.state,
        order.source,
        order.payment_status,
        h(order.delivered? ? 'shipped' : 'unshipped'),
        h(number_to_currency order.final_total, unit: order.currency.symbol),
        h(link_to 'details', edit_admin_shop_order_path(current_shop, order)),
        h(link_to 'delete', admin_shop_order_path(current_shop, order), method: :delete, data: { confirm: 'Are you sure?' } ),
      ]
    end
  end

  def orders
    @orders ||= fetch_orders
  end

  def fetch_orders
    orders = orders_list.order("#{sort_column} #{sort_direction}")
    orders = orders.page(page).per_page(per_page)
    if params[:sSearch].present?
      orders = orders.where("title like :search", search: "%#{params[:sSearch]}%")
    end
    orders
  end

  def page
    params[:iDisplayStart].to_i/per_page + 1
  end

  def per_page
    params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
  end

  def sort_column
    columns = %w[id name date_placed state source payment_status delivered final_total]
    columns[params[:iSortCol_0].to_i]
  end

  def sort_direction
    params[:sSortDir_0] == "desc" ? "desc" : "asc"
  end
end

Когда я меняю первую строку в fetch_orders к этому

orders = Order.in_process.order("#{sort_column} #{sort_direction}")

который является жестко запрограммированным эквивалентом, он действительно работает. Так что мне просто нужен правильный синтаксис

2 ответа

Решение

Краткий ответ: Если у вас есть массив, и вы хотите отсортировать его, используйте sort_by метод:

orders = orders_list.sort_by{|order| "#{order.sort_column} #{order.sort_direction}"}

Длинный ответ: причина, по которой ваш оригинальный код не работает, в том, что в этом случае

Order.in_process.order("#{sort_column} #{sort_direction}")

Вы строите запрос. in_process является именованной областью (проходящей в некоторых условиях), и .order говорит рельсам, что заказывать запрос Затем, когда у него заканчиваются цепочечные методы, запрос выполняется (запускает некоторый sql) и получает записи из БД для создания коллекции объектов.

Как только вы работаете с коллекцией объектов, вы не можете вызвать .order метод, так как он просто используется для сборки SQL-запроса. Вам нужно использовать Array#sort_by вместо. sort_by принимает блок кода, в который передается каждый объект в коллекции (как order в моем примере, но вы можете назвать это как угодно, это просто имя переменной).

Кстати, если вы просто хотите вызвать метод для всех объектов, чтобы отсортировать их, вы можете использовать "синтаксис быстрого доступа", как .sort_by(&:methodname), Это использует маленький трюк рубина под названием Symbol#to_proc ( http://railscasts.com/episodes/6-shortcut-blocks-with-symbol-to-proc).

Так, например, если был метод в порядке как

def sort_string
  "#{self.sort_column} #{self.sort_direction}"
end

тогда вы могли бы изменить свой код на

orders = orders_list.sort_by(&:sort_string)

который опрятен.

Если у вас есть массив, то вы можете сортировать следующим образом.

   orders = orders_list.sort! {|a,b| a.sort_column <=> b.sort_direction}
Другие вопросы по тегам