Rails 3.2(ActiveRecord)关联顺序与急切的加载和排序

时间:2012-08-16 18:57:29

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord arel

我在rails中遇到了这种行为,我在文档中似乎找不到。

看起来,如果将ActiveRecord查询复杂化到将基础SQL集成到“复杂”查询中(参见下文),它就不会遵守关联中指定的排序。

这是我的示例模型:

class Article < ActiveRecord::Base
  belongs_to :user
  has_many :categories, :order => :name
  attr_accessible :title, :user_id, :user
end

如果我执行“简单”查询,我可以按名称命令关联的类别:

> Article.includes(:categories).first.categories.map &:name
  Article Load (0.1ms)  SELECT "articles".* FROM "articles" LIMIT 1
  Category Load (0.2ms)  SELECT "categories".* FROM "categories" WHERE "categories"."article_id" IN (11) ORDER BY name
 => ["category 3059", "category 3212", "category 3240", "category 3651", "category 4371", "category 5243", "category 6176", "category 6235", "category 6468", "category 654", "category 6804", "category 6892", "category 7026", "category 8929", "category 9653"]

您可以看到类别的名称符合预期的顺序(注意:由于数据库对字符串进行排序,我希望3位数字的编号按字母顺序排列。)

下一个示例是使用另一个关联属性进行排序的更复杂的查询:

> Article.includes(:user, :categories).order('users.name').first.categories.map &:name
  Article Load (0.3ms)  SELECT DISTINCT "articles".id FROM "articles" LEFT OUTER JOIN "users" ON "users"."id" = "articles"."user_id" LEFT OUTER JOIN "categories" ON "categories"."article_id" = "articles"."id" ORDER BY users.name LIMIT 1
  SQL (0.2ms)  SELECT "articles"."id" AS t0_r0, "articles"."title" AS t0_r1, "articles"."user_id" AS t0_r2, "articles"."created_at" AS t0_r3, "articles"."updated_at" AS t0_r4, "users"."id" AS t1_r0, "users"."name" AS t1_r1, "users"."created_at" AS t1_r2, "users"."updated_at" AS t1_r3, "categories"."id" AS t2_r0, "categories"."name" AS t2_r1, "categories"."article_id" AS t2_r2, "categories"."created_at" AS t2_r3, "categories"."updated_at" AS t2_r4 FROM "articles" LEFT OUTER JOIN "users" ON "users"."id" = "articles"."user_id" LEFT OUTER JOIN "categories" ON "categories"."article_id" = "articles"."id" WHERE "articles"."id" IN (16) ORDER BY users.name
 => ["category 5023", "category 728", "category 3306", "category 8170", "category 5957", "category 7190", "category 4427", "category 3435", "category 1274", "category 7251", "category 7368", "category 682", "category 2918"]

正如您所看到的,当AR将查询集中到其“复杂”SQL查询之一时,categories关联的订单就会丢失。

预计会出现这种情况吗?是否记录在某个我无法找到的地方?

谢谢!

1 个答案:

答案 0 :(得分:3)

这里的事情是:你正在进行连接并通过'users.name'进行排序。

当你进行连接时,你将2个表放在一起,任何排序都会影响整个连接表。

因为你无论如何都要进行2次查询,我会这样写:

Article.includes(:user, :categories).order('users.name').first.categories.order(:name).map &:name

甚至更好,使用pluck方法。它只返回一个列值:

Article.includes(:user, :categories).order('users.name').first.categories.order(:name).pluck(:name)

这样您就不必加载所有类别属性来列出其名称。 =)

PS:

如果您想进行双重排序,可以传递两个参数来订购:

Article.includes(:user, :categories).order('users.name', 'categories.name')

我没有编写整个查询,因为我不明白你究竟想要恢复的是什么。如果你解释得更多,我可以尝试一下。到目前为止,我了解到您正在尝试获取按名称排序的所有类别(按名称排序)属于第一个用户的文章。但对我来说,没有上下文,查询就没有多大意义。