这是当前的查询:
@feed = RatedActivity.find_by_sql(["(select *, null as queue_id, 3 as model_table_type from rated_activities where user_id in (?)) " +
"UNION (select *, null as queue_id, null as rating, 2 as model_table_type from watched_activities where user_id in (?)) " +
"UNION (select *, null as rating, 1 as model_table_type from queued_activities where user_id in (?)) " +"ORDER BY activity_datetime DESC limit 100", friend_ids, friend_ids, friend_ids])
现在,这是一个很大的问题,因为实际上有一些模型设置为:
class RatedActivity < ActiveRecord::Base
belongs_to :user
belongs_to :media
end
class QueuedActivity < ActiveRecord::Base
belongs_to :user
belongs_to :media
end
class WatchedActivity < ActiveRecord::Base
belongs_to :user
belongs_to :media
end
很想知道如何在rails 3.0中使用activerecord来实现与我在那里疯狂联盟所做的基本相同的事情。
答案 0 :(得分:2)
听起来你应该将这三个独立的模型合并为一个模型。然后,根据该模型的属性隐藏“监视”,“排队”或“评级”等状态。
class Activity < ActiveRecord::Base
belongs_to :user
belongs_to :media
scope :for_users, lambda { |u|
where("user_id IN (?)", u)
}
scope :rated, where("rating IS NOT NULL")
scope :queued, where("queue_id IS NOT NULL")
scope :watched, where("watched IS NOT NULL")
end
然后,您可以拨打Activity.for_users(friend_ids)
以获取上述尝试完成的所有三个群组...或者您可以拨打Activity.for_users(friend_ids).rated
(或排队或观看)以获得一个群组。这样,您的所有Activity逻辑都合并到一个位置。您的查询变得更简单(也更有效),您不必维护三种不同的模型。
答案 1 :(得分:1)
我认为您现有的解决方案在传统数据库的情况下是可以的。作为本机查询,它也是最有效的,因为您的DBMS完成所有艰苦的工作(联合,排序,限制)。
如果您真的想在不更改架构的情况下摆脱SQL UNION,那么您可以将union移动到Ruby数组求和 - 但这可能会更慢。
result = RatedActivity.
select("*, null as queue_id, 3 as model_table_type").
where(:user_id=>friend_ids).
limit(100).all +
QueuedActivity...
最后,您需要使用
对该产品进行排序和限制result.sort(&:activity_datetime)[0..99]
这只是概念的证明,因为你看到它是低效的一些点(3个查询,在Ruby中排序,限制)。我会留在find_by_sql
。