Slide 1

Slide 1 text

ActiveRecord::Relation and Arel Rob Mack, Spiceworks Sunday, September 2, 12 Theo Mills and I built data access layer for a large Rails app. We built it on top of Active Record and Arel. ActiveRecord a bit of a leaky abstraction. You think in associations some places, but table names other places.

Slide 2

Slide 2 text

What’s Arel? • Query generation for Rails 3 • Relational Algebra (algebra of sets) • gem github://rails/arel Sunday, September 2, 12 - closure - not that closure, just means returns a set that you can operate on - creates syntax tree - leaves are relations - internal nodes are operators

Slide 3

Slide 3 text

Arel History • 2007 - Nick Kallen (Pivotal/Twitter) creates sql_algebra • 2008 - Renamed to Active Relation, then Arel • 2009 - Bryan Helmkamp (@brynary), takes over as maintainer • 2009 - Emilo Tagua - integrates it with ActiveRecord • 2010 - Aaron Patterson (@tenderlove) - starts Source: https://speakerdeck.com/u/tomstuart/p/relational-algebra-and-arel Sunday, September 2, 12 What does this have to do with Rails? Rails 2 queries were generated by string concatenation. Sql string was built up, then executed. Rails 3 changes this with Arel, but when 3.0 launched, Arel was on of the causes for the Rails 3 slowness. The original Arel stores methods calls in a link list, to generation the sql, it has to walk backwards through the list. Tenderlove changes design to abstract syntax tree with a manager object. Once you have your AST, you don't necessarily need to generate SQL, hence visitors.

Slide 4

Slide 4 text

Arel vs. ActiveRecord::Relation Sunday, September 2, 12 There's a lot of confusion about Arel vs. ActiveRecord::Relation. AR::Rel is the AR layer on top of Arel.

Slide 5

Slide 5 text

ActiveRecord::Relation • where • select • group • order • reorder • reverse_order • limit • offset • joins • includes • lock • readonly • having • uniq Sunday, September 2, 12 Active Record query interface defined in ActiveRecord::QueryMethods. All return relations.

Slide 6

Slide 6 text

What’s in it for me? • lazy evaluation • chaining • portability Sunday, September 2, 12

Slide 7

Slide 7 text

Lazy Evaluation # app/controller/user_controller.rb def index @recent_users = User.where("created_at > ?", 1.day.ago) end # app/controller/index.html.erb <% cache("recent_users") do %> <% @recent.users.each do |u| %> ... Sunday, September 2, 12 more useful on a large legacy app

Slide 8

Slide 8 text

Chaining > User.where(:id => 1).object_id => 43078 > User.where(:id => 1).object_id => 43080 User.where(:status => 'active'). where("created_at > ?", 1.day.ago). order(:created_at).limit(10) Sunday, September 2, 12 Chaining works by cloning the relation, building complex search example (app not big enough for full search solution)

Slide 9

Slide 9 text

Useful Methods > User.order(:created_at).to_sql => "SELECT users.* FROM users ORDER BY created_at" > User.unscoped.class => ActiveRecord::Relation > User.unscoped.to_sql => "SELECT users.* FROM users" Sunday, September 2, 12 Note: Arel has a to_sql method too, unscoped remove default scope, also a scoped method

Slide 10

Slide 10 text

Merge Relations inactive = User.where(:status => 'inactive') recent = User.where("created_at > ?", 1.week.ago) recent.merge(inactive).to_sql => "SELECT users.* FROM users WHERE users.status = 'active' AND (users.created_at > '2012-08-21');" Sunday, September 2, 12

Slide 11

Slide 11 text

where_values recent.merge(inactive).where_values => [, "created_at > '2012-08-21'"] joins_values select_values limit_values uniq_values order_values etc.. Sunday, September 2, 12

Slide 12

Slide 12 text

A lot like named scopes scope :active, where(:status => 'active') def self.active where(:status => 'active') end Sunday, September 2, 12 not much difference

Slide 13

Slide 13 text

Console Gotcha > User.where(:status => 'active') => doh! # File activerecord/lib/active_record/relation.rb def inspect to_a.inspect end Sunday, September 2, 12 executing this in the rails console is generally bad, use .to_sql or ;nil Inspect method calls to_a, so if you are playing with Relations on console, the output spew can be overwhelming

Slide 14

Slide 14 text

Arel Sunday, September 2, 12

Slide 15

Slide 15 text

Arel Operators • eq • not_eq • lt • lteq • gt • gteq • matches # like • not_matches • in • not_in • take # limit • skip # offset Sunday, September 2, 12

Slide 16

Slide 16 text

ActiveRecord::Base arel_table arel_engine u = User.arel_table u.class => Arel::Table Sunday, September 2, 12

Slide 17

Slide 17 text

Mix and Match u = User.arel_table User.where(u[:created_at].gt(1.day.ago)).limit(1) User.where(:id => 10).arel.class => Arel::SelectManager Sunday, September 2, 12 drop arel into relations, use arel method to get from a relation back to the underlying arel object

Slide 18

Slide 18 text

Why do I need Arel? • complex queries • complex dynamic joins, specifying table alias • compatibility Sunday, September 2, 12 Maybe you don’t

Slide 19

Slide 19 text

Visitors Arel::Visitors::PostgreSQL Arel::Visitors::MySQL Arel::Visitors::MSSQL Arel::Visitors::Oracle Arel::Visitors::SQLite Arel::Visitors::IBM_DB Arel::Visitors::Informix Sunday, September 2, 12 Visitor design pattern, separate algorithm from object structure that it operates on. Visitors traverse the AST creating SQL.

Slide 20

Slide 20 text

Portability with Visitors u = User.arel_table User.where(u[:name].matches("bob")).to_sql "users.name ILIKE 'bob'" # postgres "users.name LIKE 'bob'" #mysql Sunday, September 2, 12

Slide 21

Slide 21 text

Table Join Gotcha def self.cheaper_than(price) where("price < ?", price) end def self.cheaper_than(price) where(arel_table[:price].lt(price)) end Sunday, September 2, 12 second one will work if you are joining in multiple tables with price column, aliased table or otherwise

Slide 22

Slide 22 text

Ernie Miller • github://ernie/squeel • railscasts.com/episodes/354-squeel • erniemiller.org Sunday, September 2, 12 Ernie Miller - living social, knows a ton about arel, contributor, interesting blog before you go diving to far into Arel, take a look at the squeel gem

Slide 23

Slide 23 text

Links • Aaron Patterson on Arel 2.0 - http:// web.archive.org/web/20101113093529/http:// engineering.attinteractive.com/2010/10/arel-two- point-ohhhhh-yaaaaaa/ • History of Arel - https://speakerdeck.com/u/ tomstuart/p/relational-algebra-and-arel Sunday, September 2, 12

Slide 24

Slide 24 text

Thanks! Rob Mack, Spiceworks @robmack [email protected] Sunday, September 2, 12

Slide 25

Slide 25 text

Obligatory “We’re Hiring!” Slide Sunday, September 2, 12