在Rails中,我可以通过委托方法订购查询吗?

时间:2015-01-28 21:23:52

标签: ruby-on-rails ruby ruby-on-rails-4 delegates rails-activerecord

我很难通过委托方法订购查询。我的任务是帮助将相当大的Rails 3应用程序升级到Rails 4.我在索引操作中遇到了这个查询。 我知道这些对象的命名是可怕和令人困惑的。

# measurements_controller.rb
def index
  @measurements = Measurement.includes(:identifier).order(:name)
end

在Rails 4中,我收到此错误:

ERROR: column info_items.name does not exist LINE 1: ...D (info_item_identifiers.name LIKE '%') ORDER BY "info_item...

所以我看了一下模型,发现:

# measurement.rb
class Measurement < InfoItem
  ...
end

# info_item.rb
belongs_to :identifier, class_name: 'InfoItemIdentifier'
delegate :name, :name=, to: :identifier

# info_item_identifier.rb
# This object has a name column in the database

如果我在终端中并且我有一个Measurement的实例,我可以轻松调用.name方法并且效果很好。但是当谈到.order(:name)时,由于该列不存在而无效。

我找到了一个解决方案,但它似乎打败了委托方法的目的。在控制器中,我可以将其更改为:

@measurements = Measurement.includes(:identifier).order('info_item_identifiers.name')

由于我知道InfoItemname方法委托给InfoItemIdentifiers,我不认为我的控制器需要知道它被委派的位置。

有没有办法保留现有代码并仍按委托方法排序?

1 个答案:

答案 0 :(得分:3)

是的,但它需要首先实例化所有记录(这会降低性能)。

@measurements = Measurement.joins(:identifier).sort_by &:name

此代码加载所有测量并实例化它们,然后通过Ruby方法.name

对它们进行排序

<强>解释

delegate仅影响ActiveRecord模型的实例。它不会影响您的SQL查询。

此行直接映射到SQL查询。

Measurement.includes(:identifier).order(:name)

正如您所注意到的,它会在测量表上查找name列并且找不到任何内容。您的ActiveRecord模型实例知道name仅存在于identifier,但您的SQL数据库并不知道,因此您必须明确告知它在哪个表中找到该列。