Arel: A Quick Intro
Arel is a SQL AST (Abstract Syntax Tree-like) manager for Ruby. It allows us to write complex SQL queries in a semantic, reusable fashion. Arel is "framework framework"; it's designed to optimize object and collection modeling over database compatibility. For example, Active Record is built on top of Arel.
Arel maps our data domain into a tree-like structure. For example, we can grab a tree-like representation of the portion of our data model related to users by calling:
User.arel_tabel => #<Arel::Table:0x007fd42da94350 @aliases=, @columns=nil, @engine= User(id: integer, name: string), @name="user", @primary_key=nil, @table_alias=nil>
Arel::Table instance we can execute queries using predicates like:
users = User.arel_table User.select(users[Arel.star]).where(users[:id].eq(1))
Selecting Virtual Attributes
Yesterday I found myself needing to query for a record and add some attribute with a fixed value to that record that was not a column on the record's table. I was working on a feature to update various records in Learn.co with the awareness that a given lesson had been "deployed" to GitHub (i.e. the repo containing the lesson had been created). In order to do so, I needed to query for the lesson with a given UUID, attach the GitHub repository ID to the lesson, and pass the lesson down the chain of several other method calls in order for all of the necessary records to get updated.
There was just one problem though. The lessons table doesn't have a
github_repository_id column. If only there was some way for me to query for a lesson and temporarily attach the GitHub repo ID to the resulting record, so that this nice little package of lesson information could contain everything my code needs to do its work.
Good news! Arel can totally do this for us!
We can execute a simple
SELECT statement using Arel by first grabbing the
Lesson model's arel table and using
where with the appropriate predicate:
lessons = Lesson.arel_table Lesson .select(lessons[Arel.star]) .where(lessons[:uuid].eq("a0cea74c-302f-4a47-a096-6d04690468a9"))
Next up we want to add to our select statement. We'll tell our select statement to select all of the columns from the lessons table, and a virtual attribute with a fixed value:
# where the GitHub repo ID for the lesson is 1234 lesson = Lesson .select(lessons[Arel.star], "'1234' as 'github_repository_id'") .where(lessons[:uuid].eq("a0cea74c-302f-4a47-a096-6d04690468a9")) .first
Now we have a lesson that we can work with like this:
lesson[:github_repository_id] # => '1234'
For a more advanced look at Arel querying, check out my post Composable Query Builders in Rails with Arel