为什么ActiveRelation在调用merge时返回一个数组?

时间:2012-05-16 11:47:09

标签: ruby-on-rails ruby activerecord

我有名为UserActivityTask的模型,我可以执行以下操作

> puts Activity.joins(:task).to_sql
SELECT "activities".* FROM "activities" INNER JOIN "tasks" ON "tasks"."id" = "activities"."task_id" ORDER BY date DESC

> puts User.first.shared_tasks.to_sql
SELECT "tasks".* FROM "tasks" INNER JOIN "user_tasks" ON "tasks"."id" = "user_tasks"."task_id" WHERE "user_tasks"."user_id" = 1

但是当我尝试merge这两个时,我得到一个数组:

> puts Activity.joins(:task).merge(User.first.shared_tasks).to_sql
NoMethodError: undefined method `to_sql' for []:Array

为什么不回归关系?我需要在其上加上where子句。

更新

进一步检查后,看起来像User.first.shared_tasks正在被评估为一系列任务。我可以通过添加order调用来获得我想要的行为:

> puts Activity.joins(:task).merge(User.first.shared_tasks.order()).to_sql
SELECT "activities".* FROM "activities" INNER JOIN "tasks" ON "tasks"."id" = "activities"."task_id" INNER JOIN "user_tasks" ON "tasks"."id" = "user_tasks"."task_id" WHERE "user_tasks"."user_id" = 1 ORDER BY date DESC

除了添加空order

之外,还有更好的方法可以阻止评估该关系吗?

3 个答案:

答案 0 :(得分:2)

每当你在一个没有响应的关系对象上调用一个方法时,它就会将该方法委托给其他类型的对象。在merge的情况下,它将被转换为数组。这是通过ActiveRecord::Delegation module完成的。某些方法(例如each)为explicitly delegated,其他方法(例如merge)则通过method_missing完成。

例如,如果你这样做:

Activity.joins(:task).each { |activity| puts activity }

关系将.each委托给数组(Enumerator),基本上是进行转换。

答案 1 :(得分:1)

好吧,我还没弄清楚为什么User.first.shared_tasks会被立即评估,但我已经找到了解决方法。我可以致电scoped

> User.first.shared_tasks.class
=> Array

> User.first.shared_tasks.scoped.class
=> ActiveRecord::Relation

现在,当我尝试进行合并时:

Activity.joins(:task).merge(User.first.shared_tasks.scoped)

它使用ActiveRecord::Relation#merge代替Array#merge

答案 2 :(得分:0)

对于关系你可以尝试这个

puts (Activity.joins(:task) & User.first.shared_tasks).to_sql

merge有助于创建一个范围,并返回一个结果对象数组。