Arel:Arel :: SelectManager与join的活动关系

时间:2017-03-16 17:28:02

标签: ruby-on-rails-4 activerecord arel

让我们拥有一个Rails 4.2.x应用程序,我们有两个表格帖子和作者,我们希望使用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

现在我们可以通过执行以下操作来获取帖子的数组(类Array):

> 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

我在想我必须遗漏一些东西。简而言之:如何从上面的my_query之类的选择管理器(或另一个选择管理器完成相同的事情)获得活动记录关系。

1 个答案:

答案 0 :(得分:5)

你不能从sql字符串中获取Arel :: SelectManager的ActiveRecord :: Relation。您有两种方法通过ActiveRecord加载数据:

  1. 在Arel中执行所有查询逻辑。在这种情况下,您不能使用任何ActiveRecord :: Relation方法。但是你在Arel中有相同的功能。在您的示例中,您可以通过Arel设置限制:

    my_query.take(10)
    
  2. 其他方法是在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
    
  3. 在这种情况下,您可以使用my_query作为ActiveRecord :: Relation