我有名为User
,Activity
和Task
的模型,我可以执行以下操作
> 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
?
答案 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有助于创建一个范围,并返回一个结果对象数组。