【问题标题】:Which association is sorted in that line of code?该行代码中对哪个关联进行了排序?
【发布时间】:2016-05-18 18:36:43
【问题描述】:

如果Input 模型has_many :translations,对哪个翻译行进行排序?

Input.includes(:translations).order("translations.value DESC")

模型

class Input < ActiveRecord::Base
  has_many :translations, dependent: :destroy
end

class Translation < ActiveRecord::Base
  belongs_to :input
  belongs_to :language
end

# translations table schema:
# id          :integer
# value       :string
# input_id    :integer
# language_id :integer

我需要列出所有输入,有 8 列(针对我与翻译相关联的 8 种语言)按第一语言的翻译值排序(任意设置)。

【问题讨论】:

    标签: ruby-on-rails ruby postgresql sorting associations


    【解决方案1】:

    translations 表的 value 列。它将生成如下所示的 SQL:

    SELECT "inputs"."id" AS t0_r0, "inputs"."name" AS t0_r1, ..., 
        "translations"."id" AS t1_r0, "translations"."value" AS t1_r1, ...
    FROM "inputs"
    LEFT OUTER JOIN "translations"
        ON "translations"."input_id" = "inputs"."id"  
    ORDER BY translations.value DESC   // <== YOUR `.order()` method
    

    如您所见,排序是在 DB 中完成的,而不是在 Rails 中完成的。因此,排序将是您的 DB 排序。

    【讨论】:

    • 但是一个输入可以有多个翻译,那么排序算法使用的是哪一个?
    • @ViniciusFontoura 排序使用所有。每个“输入”在您显示的查询中可能会出现不止一次。
    • 我明白了。我用更多信息和上下文更新了问题。提前致谢。
    • 我添加了一张图片。
    【解决方案2】:

    为了回答您的第一个问题,您的 Input 表的所有行都用于连接 Translations 表,因此所有连接的行都将按 Translations 表中的value 排序。

    由于您没有为输入表的查询提供任何where 条件,因此输入表中的所有行都将被使用,这听起来像是您的意图。

    您在查询中使用了includes,而您几乎可以肯定的意思是joins。虽然它们在许多情况下在语法上是可以互换的,但它们在语义上是用于不同的目的。

    includes 是专门为促进eager loading 而提供的,而joins 是为了支持joining tables 而定义的。经验法则是,如果您想在查询中使用连接表中的任何列,请使用joins,否则,您可以使用includes 预加载关联。

    仅使用 SQL 很难实现您想要获得的结果。但是,您可以轻松获取 Input 行和关联,并使用简单的 Ruby 集合转换来获取您想要的结果,包括 Translations 中缺失值的占位符。

    试试这个:

    languages = Language.all.order("name")
    inputs = Input.includes(:translations).order("id")
    translations = inputs.map do |input|
      { 
        input.id => languages.map do |language| 
                      item = input.translations.find_index {|i| i.language_id == language.id }
                      item ? nil : input.translations[item]
                    end
      }
    end
    

    这将返回一个哈希数组,它以 input.id 作为键,并为每个提供的 8 列表翻译。 nil 用作输入不存在的翻译的占位符,因此您可以将其用作视图中的指示以插入“翻译...”选项。可以这样使用:

    <table>
    <% inputs.each do |input| %>
        <tr>
        <% translation = translations[input.id] %>
        <% translation.each do |item| %>
          <% item %>
              <td class="translation-available"><%= item.value %></td>
          <% else %>
              <td><%= link_to "Translate...", translate_input_path(input) %></td>
          <% end %>
        </tr>
    <% end %>
    

    显然,我在一些结构和设计元素中进行了模拟,以便向您展示如何处理inputs 数组;您可以根据需要对其进行调整以适应您的视图结构。

    【讨论】:

    • 谢谢,输入表工作正常。现在,如何按语言按字母顺序对输入进行排序?
    • 代码的第一行是languages = Language.all.order("name")。如果您更改用于订购的字段,它将更改此处显示的语言的顺序。我假设您的语言模型有一个 name 字段,但您可以将最适合您的字段放在这里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-11
    相关资源
    最近更新 更多