Rails - 将集合传递给ActiveModel对象

时间:2014-03-11 09:37:37

标签: ruby-on-rails ruby parameters datatables activemodel

我使用rails来创建一个用Ajax分页的datatable,我正在关注railscast #340这样做。

本集使用名为ProductsDatatable的普通ActiveModel类或我的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 个答案:

答案 0 :(得分:0)

简短回答:如果您有一个数组,并想要对其进行排序,请使用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告诉rails要查询的内容。然后,当它用完链式方法时,查询执行(运行一些sql)并从数据库中获取记录以构建对象集合。

一旦使用了一组对象,就不能在其上调用.order方法,因为它只是用来组装一个sql查询。您需要使用Array#sort_by代替。 sort_by接受一个代码块,其中传递集合中的每个对象(在我的示例中为order但你可以调用它,它只是一个变量名)。

顺便说一句,如果你只想在所有对象上调用一个方法来对它们进行排序,你可以使用像.sort_by(&:methodname)这样的“快捷语法”。这使用了一个名为Symbol#to_prochttp://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)

这很整洁。

答案 1 :(得分:0)

如果您有阵列,那么您可以这样排序。

   orders = orders_list.sort! {|a,b| a.sort_column <=> b.sort_direction}