Arel:加入 table,在加入的字段上排序

Arel: join table, sort on joined field

我有以下 ActiveRecord 模型

class Publication < ActiveRecord::Base
   attr_accessible :id, :pname

   has_many :advertisements
end

class Vendor < ActiveRecord::Base
   attr_accessible :id, :vname
   has_many :advertisements
end

class Advertisement < ActiveRecord::Base
  attr_accessible :id, :vendor_id, :publication_id, :prose, :aname
  belongs_to :vendor
  belongs_to :publication

end

它们的 tables 具有与其可访问属性相同的字段。

我希望能够按出版物名称、广告名称或供应商名称进行升序或降序排序。

我还有一个广告控制器,我想在其中显示广告列表。该列表显示广告名称 (aname)、广告内容 (prose)、供应商名称 (vname) 和出版物名称 (pname)。

按出版物名称排序的 SQL 查询类似于:

SELECT ads.aname AS aname, ads.id, ads.prose, ven.vname AS vname, pub.pname AS pname  
    FROM advertisements AS ads
      INNER JOIN publications AS pub ON ads.publication_id = pub.id
      INNER JOIN vendors AS ven ON ads.vendor_id = ven.id
      ORDER BY <sort_column> <sort_order>

其中 sort_column 可以是 "pname"、"aname" 或 "vname" 之一,而 sort_order 可以是 "ASC" 或"DESC",两者都将作为来自 Web 表单的参数以及分页页码。

控制器索引代码看起来这样的:

class AdvertisementsController < ApplicationController
   def index
     sort_column = params[:sort_column]
     sort_order = params[:sort_order]

     @ads = Advertisement.join( somehow join tables)
               .where(some condition).where(some other condition)
               .order("#{sort_column} #{sort_order}")      ### I don't know what to do here
               .paginate(page: params[:page], per_page: 10) #from will_paginate

   end

   #   other controller methods.......
end

索引视图 table 片段(用 SLIM 编写)如下所示:

tr
- @ads.each do |ad|
  td = ad.id
  td = ad.aname
  td = ad.pname
  td = ad.vname

我知道我可以使用 AREL 来执行此操作,但我一直在 Rails 控制台中尝试使用 AREL 来生成和执行带有分页的查询,并阅读网络上的教程和我不知道如何在 AREL 中获取此查询,对连接字段进行排序,并能够使用 will_paginate Ruby 查询子句对查询进行分页。

如何使用 AREL,甚至 ActiveRecord 来做到这一点?我感谢我能得到的任何帮助。

您可以使用 vanilla ActiveRecord 方法完成您想要的,而无需 Arel。您所拥有的非常接近,这可能会帮助您实现目标。

# whitelist incoming params
sort_column = %w(pname aname vname).include?(params[:sort_column]) ? params[:sort_column] : "pname"
sort_order  = %w(asc desc).include?(params[:sort_order])           ? params[:sort_order]  : "desc"

@ads = Advertisement.select("advertisements.*, vendors.vname, publications.pname").
  joins(:publication, :vendor).
  where(some condition).
  where(some other condition).
  order("#{sort_column} #{sort_order}").
  page(params[:page]).per_page(10)

您可以使解决方案同时适用于 Arel 和 ActiveRecord。我建议您尽可能多地使用 ActiveRecord,除非您不能使用 AR。

A​​rel 很棒,但最近我发现在我的代码库中,它降低了整体可读性,尤其是如果您将它与 AR 混合使用或使用过多。

还有一些其他建议:

  1. 关于尝试使用 "includes" 而不是 "joins" 的相同查询。您可能认为它比必须添加 select 子句更容易。 outerjoins我用的是includes,不过比较详细,google"includes vs joins",很有意思

  2. 与我的第一个建议完全相反,如果您的查询变得复杂,我强烈建议您使用 https://github.com/activerecord-hackery/ransack or https://github.com/activerecord-hackery/squeel 作为您的用例。 特别是如果您不只是为了学习目的而执行上述操作。