Arel:来自 Arel::SelectManager 的活跃关系与加入
Arel: active relation from Arel::SelectManager with join
让我们有一个 Rails 4.2.x 应用程序,我们有两个表 posts 和 authors,我们想使用 Arel 来获取由姓名 == 作者撰写的帖子'Karl'。
(在这种情况下,我们会对 Active Record 连接感到满意,但这只是为了让示例保持简单。)
posts = Arel::Table.new :posts
authors = Arel::Table.new :authors
my_query = posts.project(Arel.star)
.join(authors)
.on(posts[:author_id].eq(authors[:id]))
.where(authors[:name].eq('Karl'))
> my_query.class
=> Arel::SelectManager
现在我们可以通过以下操作取回一个帖子数组(class 数组):
> Post.find_by_sql my_query
[master] Post Load (3.1ms) SELECT * FROM "posts" INNER JOIN "authors"
ON "posts"."author_id" = "authors"."id"
WHERE "authors"."name" = 'Karl'
=> [#<Post:0x005612815ebdf8
id: 7474,
...
]
所以我们确实得到了一组帖子,而不是一个活动记录关系:
> Post.find_by_sql(my_query).class
=> Array
同样将管理器注入 Post.where 也行不通
> Post.where my_query
=> #<Post::ActiveRecord_Relation:0x2b13cdc957bc>
> Post.where(my_query).first
ActiveRecord::StatementInvalid: PG::SyntaxError:
ERROR: subquery must return only one column
SELECT "posts".* FROM "posts"
WHERE ((SELECT * FROM "posts" INNER JOIN "authors" ON "posts"."author_id" = "authors"."id" WHERE "authors"."name" = 'Karel'))
ORDER BY "posts"."id" ASC LIMIT 1
我想我一定是漏掉了什么。简而言之:如何从 select 经理(如上面的 my_query(或另一个 select 经理完成同样的事情)那里获得活动记录关系。
您无法从 Arel::SelectManager 或 sql 字符串中获取 ActiveRecord::Relation。你有两种方式通过ActiveRecord加载数据:
在 Arel 中执行所有查询逻辑。在这种情况下,您不能使用任何 ActiveRecord::Relation 方法。但是您在 Arel 中具有相同的功能。在您的示例中,您可以通过 Arel 设置限制:
my_query.take(10)
其他方法是在 ActiveRecord::Relation 方法中使用 Arel。您可以这样重写您的查询:
posts = Arel::Table.new :posts
authors = Arel::Table.new :authors
join = posts.join(authors).
on(posts[:author_id].eq(authors[:id])).
join_sources
my_query = Post.
joins(join).
where(authors[:name].eq('Karl'))
> my_query.class
=> ActiveRecord::Relation
在这种情况下,您可以将 my_query
用作 ActiveRecord::Relation
让我们有一个 Rails 4.2.x 应用程序,我们有两个表 posts 和 authors,我们想使用 Arel 来获取由姓名 == 作者撰写的帖子'Karl'。 (在这种情况下,我们会对 Active Record 连接感到满意,但这只是为了让示例保持简单。)
posts = Arel::Table.new :posts
authors = Arel::Table.new :authors
my_query = posts.project(Arel.star)
.join(authors)
.on(posts[:author_id].eq(authors[:id]))
.where(authors[:name].eq('Karl'))
> my_query.class
=> Arel::SelectManager
现在我们可以通过以下操作取回一个帖子数组(class 数组):
> Post.find_by_sql my_query
[master] Post Load (3.1ms) SELECT * FROM "posts" INNER JOIN "authors"
ON "posts"."author_id" = "authors"."id"
WHERE "authors"."name" = 'Karl'
=> [#<Post:0x005612815ebdf8
id: 7474,
...
]
所以我们确实得到了一组帖子,而不是一个活动记录关系:
> Post.find_by_sql(my_query).class
=> Array
同样将管理器注入 Post.where 也行不通
> Post.where my_query
=> #<Post::ActiveRecord_Relation:0x2b13cdc957bc>
> Post.where(my_query).first
ActiveRecord::StatementInvalid: PG::SyntaxError:
ERROR: subquery must return only one column
SELECT "posts".* FROM "posts"
WHERE ((SELECT * FROM "posts" INNER JOIN "authors" ON "posts"."author_id" = "authors"."id" WHERE "authors"."name" = 'Karel'))
ORDER BY "posts"."id" ASC LIMIT 1
我想我一定是漏掉了什么。简而言之:如何从 select 经理(如上面的 my_query(或另一个 select 经理完成同样的事情)那里获得活动记录关系。
您无法从 Arel::SelectManager 或 sql 字符串中获取 ActiveRecord::Relation。你有两种方式通过ActiveRecord加载数据:
在 Arel 中执行所有查询逻辑。在这种情况下,您不能使用任何 ActiveRecord::Relation 方法。但是您在 Arel 中具有相同的功能。在您的示例中,您可以通过 Arel 设置限制:
my_query.take(10)
其他方法是在 ActiveRecord::Relation 方法中使用 Arel。您可以这样重写您的查询:
posts = Arel::Table.new :posts authors = Arel::Table.new :authors join = posts.join(authors). on(posts[:author_id].eq(authors[:id])). join_sources my_query = Post. joins(join). where(authors[:name].eq('Karl')) > my_query.class => ActiveRecord::Relation
在这种情况下,您可以将 my_query
用作 ActiveRecord::Relation