Let us we have a Rails 4.2.x app and we have two tables posts and authors, and we want to use Arel to get the posts authored by an author with name == 'Karl'. (In this case we could be happy with Active Record joins but this is just to keep the example simple.)
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
Now we could get back an array (of class Array) of posts by doing:
> 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,
...
]
So we do get an array of posts, not an active record relation:
> Post.find_by_sql(my_query).class
=> Array
Also injecting the manager into Post.where won't work
> 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
I am thinking I must be missing something. In short: how do you get an active record relation from a select manager like my_query above (or another select manager accomplishing the same thing).
Arel is an AST manager used in ActiveRecord to create SQL query. Every SQL statements are represented as ruby code in Arel. Because of this, it enable to write a complicated SQL query without using raw SQL string. But it's not recommended to use Arel in the application because it's a private API.
Arel is a library that was introduced in Rails 3 for use in constructing SQL queries. Every time you pass a hash to where, it goes through Arel eventually. Rails exposes this with a public API that we can hook into when we need to build a more complex query.
Arel is a powerful SQL AST manager that lets us appropriately combine selection statements for simple to very complicated queries. However, reader be cautioned – Arel is still a private API provided by Rails. Meaning that future versions of Rails could be subject to changes in Arel.
You can't get ActiveRecord::Relation from Arel::SelectManager neither from sql string. You have two ways to load data through ActiveRecord:
Do all query logic in Arel. In this case you can't use any of ActiveRecord::Relation methods. But you have same functionality in Arel. In your example you may set limit through Arel:
my_query.take(10)
Other way is to use Arel in ActiveRecord::Relation methods. You may rewrite your query like this:
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
In this case you may use my_query
as ActiveRecord::Relation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With