我遇到与ICTylor's post here类似的情况。
所以我有:
user1=User.find(1);
user2=User.find(2);
written=Micropost.where("user_id=2");
written.class #=> ActiveRecord::Relation
written.length #=> 50
replied=Micropost.where("response = 2 ") #=> 1
replied.class #=> ActiveRecord::Relation
现在,如果我:
alltogether= written + replied;
alltogether.class #=> Array
alltogether.length #=> 51
但是我想要的东西相当于:
all_sql= Micropost.where("user_id = 2 OR response = 2")
all_sql.class #=> ActiveRecord::Relation
all_sql.length #=> 51
换句话说我想以某种方式追加一个Micropost.where(...)
找到的记录到另一个Micropost.where(...)
找到的记录 ActiveRecord :: Relation 对象。导致相当于 all_sql ,但分两步完成。
一点解释。此部分应用程序旨在为回复消息提供类似于Twitter的功能。
例如:当User.id = 1
的用户将此邮件发送至User.id=2
时:
@2: hey this is a reply.
应用程序将使用以下参数创建Micropost
:
@post= Micropost.create(user:1, content:"@2: hey this is a reply", response: 2)
所以response
只是表示回复的 receiver id。如果邮件不是回复类型,则为response = nil
。
遵循这个想法,我希望能够:
def replies_to(user)
Micropost.where("response = #{user.id}")
end
def written_posts_by(user)
Micropost.where("user_id = #{user.id}")
end
def interesting_posts(user)
replies= replies_to(user)
written= written_posts_by(user)
#And now the question arises!
new_relation= replies union written#<---How can I do this!?
end
答案 0 :(得分:1)
This blog post讨论了此问题,并提供patch以在ActiveRecord中启用可链接的联盟。
答案 1 :(得分:1)
我认为现在有一种方法可以在ActiveRecord :: Relation上使用内置的Rails来建立联合。你最好用OR写一个查询,即使它不是那么干。
使用arel:
def interesting_posts(user)
posts = Micropost.arel_table
Micropost.where(posts[:response].eq(user.id).or(posts[:user_id].eq(user.id)))
end
使用SQL:
def interesting_posts(user)
Micropost.where('response = ? OR user_id = ?', user.id, user.id)
end
答案 2 :(得分:1)
设计本身存在一些问题,如果帖子回复两个或更多接收者怎么办?表中也会有太多的空数据,这是不好的。
无论如何,基于当前的设计仅允许一个接收器,模型需要进行一些更改。
class User < ActiveRecord::Base
has_many :posts
has_many :replies, class_name: 'Post', foreign_key: 'response_id'
def written_posts
posts
end
def posts_replied_to_me
replies
end
end
上述变化的注释:
(user)
现在为interesting_posts
。由于上述重构,您不再依赖上述方法来构建聚合查询,因为它们具有不同的结构。如Mori所提到的那样修补是一种解决方案,但如果可能的话,我自己也不愿意触摸libs。
我更希望使用一种方法来聚合专用于此案例的查询。
def interested_posts
Post.where(interesting_criteria)
end
private
def interesting_criteria
conditions = []
conditions << written_by_me
conditions << replied_to_me
conditions << foo_bar
conditions.join(' AND ')
end
def written_by_me
"user_id = #{self.id}"
end
def replied_to_me
"response_id = #{self.id}"
end
def foo_bar
"feel free to add more"
end