Skip to content

Instantly share code, notes, and snippets.

@trptcolin
Last active December 21, 2015 02:28
Show Gist options
  • Save trptcolin/6234896 to your computer and use it in GitHub Desktop.
Save trptcolin/6234896 to your computer and use it in GitHub Desktop.
# General comment: I assume here that I'm just doing it wrong as I haven't been using Arel that long.
# If I knew for sure this was broken I'd just file a bug instead.
# Note that these specific ActiveRelations are just a trimmed-down example; the actual use case would
# really be better with a UNION, I promise.
1.9.3-p448 :301 > users = User.where(:email => "one@two.com").union(User.where(:email => "foo@bar.com"))
# => #<Arel::Nodes::Union:0x8d1e608 @left=#<Arel::Nodes::SelectStatement:0x8d1eb58 @cores=[#<Arel::Nodes::SelectCore:0x8d1eb44 @source=#<Arel::Nodes::JoinSource:0x8d1eb30 @left=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, @right=[]>, @top=nil, @set_quantifier=nil, @projections=[#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="*">], @wheres=[#<Arel::Nodes::And:0x8d1e9b4 @children=[#<Arel::Nodes::Equality:0x8d1f404 @left=#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="email">, @right="one@two.com">]>], @groups=[], @having=nil>], @orders=[], @limit=nil, @lock=nil, @offset=nil, @with=nil>, @right=#<Arel::Nodes::SelectStatement:0x8d1e888 @cores=[#<Arel::Nodes::SelectCore:0x8d1e874 @source=#<Arel::Nodes::JoinSource:0x8d1e860 @left=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, @right=[]>, @top=nil, @set_quantifier=nil, @projections=[#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="*">], @wheres=[#<Arel::Nodes::And:0x8d1e6e4 @children=[#<Arel::Nodes::Equality:0x8d1ebf8 @left=#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="email">, @right="foo@bar.com">]>], @groups=[], @having=nil>], @orders=[], @limit=nil, @lock=nil, @offset=nil, @with=nil>>
1.9.3-p448 :302 > users.count
# => 1
1.9.3-p448 :303 > users.first
# => #<Arel::Nodes::Union:0x8d1e608 @left=#<Arel::Nodes::SelectStatement:0x8d1eb58 @cores=[#<Arel::Nodes::SelectCore:0x8d1eb44 @source=#<Arel::Nodes::JoinSource:0x8d1eb30 @left=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, @right=[]>, @top=nil, @set_quantifier=nil, @projections=[#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="*">], @wheres=[#<Arel::Nodes::And:0x8d1e9b4 @children=[#<Arel::Nodes::Equality:0x8d1f404 @left=#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="email">, @right="one@two.com">]>], @groups=[], @having=nil>], @orders=[], @limit=nil, @lock=nil, @offset=nil, @with=nil>, @right=#<Arel::Nodes::SelectStatement:0x8d1e888 @cores=[#<Arel::Nodes::SelectCore:0x8d1e874 @source=#<Arel::Nodes::JoinSource:0x8d1e860 @left=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, @right=[]>, @top=nil, @set_quantifier=nil, @projections=[#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="*">], @wheres=[#<Arel::Nodes::And:0x8d1e6e4 @children=[#<Arel::Nodes::Equality:0x8d1ebf8 @left=#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0x9b6d628 @name="users", @engine=User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, company_id: integer, locale: string, authentication_token: string), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name="email">, @right="foo@bar.com">]>], @groups=[], @having=nil>], @orders=[], @limit=nil, @lock=nil, @offset=nil, @with=nil>>
1.9.3-p448 :304 > users.methods.sort - Object.methods
# => [:all?, :and, :any?, :chunk, :collect, :collect_concat, :count, :create_and, :create_false, :create_join, :create_on, :create_string_join, :create_table_alias, :create_true, :cycle, :detect, :drop, :drop_while, :each, :each_cons, :each_entry, :each_slice, :each_with_index, :each_with_object, :entries, :exclude?, :find, :find_all, :find_index, :first, :flat_map, :grep, :group_by, :grouping, :index_by, :inject, :left, :left=, :lower, :many?, :map, :max, :max_by, :member?, :min, :min_by, :minmax, :minmax_by, :none?, :not, :one?, :or, :partition, :reduce, :reject, :reverse_each, :right, :right=, :select, :slice_before, :sort, :sort_by, :sum, :take, :take_while, :to_a, :to_set, :to_sql, :zip]
1.9.3-p448 :305 > users.to_sql
#TypeError: Cannot visit Arel::Nodes::Union
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/arel-3.0.2/lib/arel/visitors/visitor.rb:25:in `rescue in visit'
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/arel-3.0.2/lib/arel/visitors/visitor.rb:19:in `visit'
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/arel-3.0.2/lib/arel/visitors/visitor.rb:5:in `accept'
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/arel-3.0.2/lib/arel/visitors/to_sql.rb:19:in `accept'
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/arel-3.0.2/lib/arel/nodes/node.rb:35:in `to_sql'
# from (irb):303
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
# from /usr/local/rvm/gems/ruby-1.9.3-p448@espl/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
# from script/rails:6:in `require'
# from script/rails:6:in `<main>'
# WHAT?!
# Seems like https://github.com/rails/arel/blob/v3.0.2/lib/arel/visitors/to_sql.rb#L162-L168 implies
# this is at least intended to work. Requiring 'arel/visitors/to_sql' doesn't change the result. In
# addition to digging through the Arel code, I've done some due diligence in the googles and saw a
# few StackOverflow questions and Rails/Arel issues around similar things, but haven't seen any real
# solutions.
1.9.3-p448 :306 > users.right.to_sql
# => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"email\" = 'foo@bar.com'"
1.9.3-p448 :307 > users.left.to_sql
# => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"email\" = 'one@two.com'"
# So, I've got a few worthwhile methods here, but c'mon...
@trptcolin
Copy link
Author

OK, traced it down, and I think the fix is rails/arel#204, in case anyone else comes across this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment