Rails, scope, OR and joins - ruby-on-rails

I have a scope:
includes(:countries).where("profiles.sector = :sector OR advices.sector = :sector", :sector => sector)
It produces the following SQL:
SELECT `profiles`.* FROM `profiles` INNER JOIN `advices` ON `advices`.`profile_id` = `profiles`.`id` WHERE (profiles.sector = 'Forestry_paper' OR advices.sector = 'Forestry_paper')
(yes I have country in my Profile and in my Country model)
Unfortunately, the OR seems to fail:
it doesn't render a profile having only the proper sector but no related advice. Thoughts?

You are doing an INNER JOIN, so it requires that the profiles have a corresponding advice. Try the following instead:
Profile
.joins("LEFT JOIN advices ON advices.profile_id = profiles.id")
.where("profiles.sector = :sector OR advices.sector = :sector", :sector => sector)
This will also include profiles that have no advices.

You can do outer joins by specifying a where clause with a hash after the includes:
Post.includes(:comments).where(:comments=>{:user_id=>nil})
produces:
Post Load (0.5ms) SELECT "posts"."id" AS t0_r0, "posts"."created_at" AS t0_r1,
"posts"."updated_at" AS t0_r2, "comments"."id" AS t1_r0, "comments"."user_id"
AS t1_r1, "comments"."post_id" AS t1_r2, "comments"."content" AS t1_r3,
"comments"."created_at" AS t1_r4, "comments"."updated_at" AS t1_r5
FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
WHERE ("comments"."user_id" IS NULL)
Ryan Bigg wrote a helpful blog post about this.
EDIT
Be aware that this technique is more or less a side effect of the way Rails constructs the SQL for eager-loading associations. An explicit LEFT JOIN is more robust, as suggested in the accepted answer.

Check out http://metautonomo.us/projects/metawhere/ for more query goodness...
meta_where is now unmaintained: https://github.com/activerecord-hackery/meta_where
Rails 5 is introducing OR statements:
Rails 5: ActiveRecord OR query

Related

I want to join tables and sort them with Geocoder Gem

What I want to solve
I want to combine the Area Model, Shop Model, and Account Model and get the results sorted in order of proximity from the location specified by the Geocoder Gem.
I want to list the results using each in a view.
However, I get a no such column: distance error as shown below.
In this case, no error will occur.
irb(main):043:0> Area.eager_load(:shop).near("tokyo")
SQL (0.4ms) SELECT areas.*, (69.09332411348201 * ABS(areas.latitude - 35.6828387) * 0.7071067811865475) + (59.836573914187355 * ABS(areas.longitude - 139.7594549) * 0.7071067811865475) AS distance, CASE WHEN (areas.latitude >= 35.6828387 AND areas.longitude >= 139.7594549) THEN 45.0 WHEN (areas.latitude < 35.6828387 AND areas.longitude >= 139.7594549) THEN 135.0 WHEN (areas.latitude < 35.6828387 AND areas.longitude < 139.7594549) THEN 225.0 WHEN (areas.latitude >= 35.6828387 AND areas.longitude < 139.7594549) THEN 315.0 END AS bearing, "areas"."id" AS t0_r0, "areas"."prefectures" AS t0_r1, "areas"."municipalities" AS t0_r2, "areas"."house_number" AS t0_r3, "areas"."building_name" AS t0_r4, "areas"."postal_code" AS t0_r5, "areas"."created_at" AS t0_r6, "areas"."updated_at" AS t0_r7, "areas"."latitude" AS t0_r8, "areas"."longitude" AS t0_r9, "shops"."id" AS t1_r0, "shops"."shop_name" AS t1_r1, "shops"."created_at" AS t1_r2, "shops"."updated_at" AS t1_r3, "shops"."shop_type_id" AS t1_r4, "shops"."station_id" AS t1_r5, "shops"."area_id" AS t1_r6 FROM "areas" LEFT OUTER JOIN "shops" ON "shops"."area_id" = "areas"."id" WHERE (areas.latitude BETWEEN 35.3933751337783 AND 35.972302266221696 AND areas.longitude BETWEEN 139.40308602609107 AND 140.11582377390894) ORDER BY distance ASC LIMIT ? [["LIMIT", 11]]
In this case, an error will occur
I want this to work.
irb(main):045:0> Area.eager_load(shop: :accounts).near("tokyo")
SQL (3.3ms) SELECT DISTINCT "areas"."id" FROM "areas" LEFT OUTER JOIN "shops" ON "shops"."area_id" = "areas"."id" LEFT OUTER JOIN "accounts" ON "accounts"."shop_id" = "shops"."id" WHERE (areas.latitude BETWEEN 35.3933751337783 AND 35.972302266221696 AND areas.longitude BETWEEN 139.40308602609107 AND 140.11582377390894) ORDER BY distance ASC LIMIT ? [["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: distance)
Environment
Ruby 2.6.3
Rails 6.0.3
Geocoder Gem: <https://github.com/alexreisner/geocoder>
Model association
# app/models/area
has_one :shop
# app/models/shop
belongs_to :shop_type
belongs_to :area
belongs_to :station
has_many :accounts
has_many :posts
# app/models/account
belongs_to :shop, optional: true
has_many :post
Addition
I tried the below, but it failed.
irb(main):001:0> Area.near("tokyo").eager_load(shop: :accounts)
(0.9ms) SELECT sqlite_version(*)
SQL (0.4ms) SELECT DISTINCT "areas"."id" FROM "areas" LEFT OUTER JOIN "shops" ON "shops"."area_id" = "areas"."id" LEFT OUTER JOIN "accounts" ON "accounts"."shop_id" = "shops"."id" WHERE (areas.latitude BETWEEN 35.3933751337783 AND 35.972302266221696 AND areas.longitude BETWEEN 139.40308602609107 AND 140.11582377390894) ORDER BY distance ASC LIMIT ? [["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: distance)
irb(main):002:0> Area.near("tokyo").eager_load(shop: :accounts)
SQL (0.3ms) SELECT DISTINCT "areas"."id" FROM "areas" LEFT OUTER JOIN "shops" ON "shops"."area_id" = "areas"."id" LEFT OUTER JOIN "accounts" ON "accounts"."shop_id" = "shops"."id" WHERE (areas.latitude BETWEEN 35.3933751337783 AND 35.972302266221696 AND areas.longitude BETWEEN 139.40308602609107 AND 140.11582377390894) ORDER BY distance ASC LIMIT ? [["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: distance)
irb(main):003:0>
The documentation mentions,
You cannot use the near scope with another scope that provides an
includes option because the SELECT clause generated by near will
overwrite it (or vice versa).
Instead of using includes to reduce the number of database queries,
try using joins with either the :select option or a call to preload.
For example:
So, maybe try Area.near("tokyo").eager_load(shop: :accounts) or Area.near("tokyo").joins(shop: :accounts) and see if that works?

Avoiding double query when eager loading Active Record association?

In order to make a single DB query, I am eager loading Posts along with their translation data (using Rails 6 and Mobility (*)), but instead it yields 2 SQL queries:
# app/models/post.rb
class Post < ApplicationRecord
extend Mobility
translates :title, :description, backend: :table
end
# app/controllers/posts_controller.rb
class PostsController < ApplicationRecord
def index
#posts = Post.eager_load(:translations).limit(3)
end
end
<%# app/views/posts/index.html.erb %>
<% #posts.each do |post| %>
<h1><%= post.title %></h1>
<div><%= post.description %></div>
<% end %>
Result:
first, all Post IDs are selected
then all attributes of posts with those IDs are returned, using WHERE IN
SELECT DISTINCT "posts"."id" FROM "posts"
LEFT OUTER JOIN "post_translations"
ON "post_translations"."post_id" = "posts"."id" LIMIT $1 [["LIMIT", 3]]
SELECT "posts"."id" AS t0_r0, "posts"."created_at" AS t0_r1, "posts"."updated_at" AS t0_r2, "post_translations"."id" AS t1_r0, "post_translations"."locale" AS t1_r1, "post_translations"."created_at" AS t1_r2, "post_translations"."updated_at" AS t1_r3, "post_translations"."title" AS t1_r4, "post_translations"."description" AS t1_r5, "post_translations"."post_id" AS t1_r6 FROM "posts"
LEFT OUTER JOIN "post_translations"
ON "post_translations"."post_id" = "posts"."id"
WHERE "posts"."id" IN ($1, $2, $3) [["id", "00060a7d-b846-5fc5-a372-1fc3462c695c"], ["id", "008db504-6fb4-5e90-bdca-4293ebe6d920"], ["id", "034944c1-4067-5ae5-89aa-4777ef14d66b"]]
How can this double SQL statement with in-memory of IDs be avoided?
(*) A note mon Mobility
The Mobility documentation has examples yielding a single SQL statement, but as pointed out by Chris Salzberg, its query API is not used at all in this example so should not be the culprit. To try to demonstrate that the issue might not be related to Mobility but Active Record itself, below is a somewhat equivalent code stripped off of Mobility, which shows the same double-querying issue (NB: this is just for demonstration purposes, as I do want to keep using Mobility):
class Post < ApplicationRecord
has_many :translations, ->{ where(locale: I18n.locale) }
%i(title description).each do |attr|
define_method(attr) do
translations.first.send(attr)
end
end
class Translation < ApplicationRecord; end
end
<%# app/views/posts/index.html.erb %>
<% Post.eager_load(:translations).limit(3).each do |post| %>
<h1><%= post.title %></h1>
<div><%= post.description %></div>
<% end %>
If incase you are trying to get some very specific attributes from your collection, then the CollectionProxy would provide you with single query. If none of the attributes(columns) are provided, it does a distinct query before doing the OUTER JOIN query.
Honestly I haven't read through the whole implementation to confirm the reasoning behind it.
But let me show you one thing.
2.5.1 :037 > Post.eager_load(:translations).each do |post|
2.5.1 :038 > puts post.title
2.5.1 :039?> end
SQL (0.5ms) SELECT "posts"."id" AS t0_r0, "posts"."title" AS t0_r1, "posts"."created_at" AS t0_r2, "posts"."updated_at" AS t0_r3, "post_translations"."id" AS t1_r0, "post_translations"."title" AS t1_r1, "post_translations"."content" AS t1_r2, "post_translations"."locale" AS t1_r3, "post_translations"."post_id" AS t1_r4, "post_translations"."created_at" AS t1_r5, "post_translations"."updated_at" AS t1_r6 FROM "posts" LEFT OUTER JOIN "post_translations" ON "post_translations"."post_id" = "posts"."id"
title 1
title 2
title 3
title 4
In this above case, you can see the eager_load does what you are expecting. The similar case where you don't mention the needed attributes, I think when it lazy evaluates, it picks up a distinct query in addition to the OUTER JOIN query
2.5.1 :040 > Post.eager_load(:translations)
SQL (0.3ms) SELECT DISTINCT "posts"."id" FROM "posts" LEFT OUTER JOIN "post_translations" ON "post_translations"."post_id" = "posts"."id" LIMIT ? [["LIMIT", 11]]
SQL (0.5ms) SELECT "posts"."id" AS t0_r0, "posts"."title" AS t0_r1, "posts"."created_at" AS t0_r2, "posts"."updated_at" AS t0_r3, "post_translations"."id" AS t1_r0, "post_translations"."title" AS t1_r1, "post_translations"."content" AS t1_r2, "post_translations"."locale" AS t1_r3, "post_translations"."post_id" AS t1_r4, "post_translations"."created_at" AS t1_r5, "post_translations"."updated_at" AS t1_r6 FROM "posts" LEFT OUTER JOIN "post_translations" ON "post_translations"."post_id" = "posts"."id" WHERE "posts"."id" IN (?, ?, ?, ?) [["id", 1], ["id", 2], ["id", 3], ["id", 4]]
=> #<ActiveRecord::Relation [#<Post id: 1, title: nil, created_at: "2021-07-08 12:42:13", updated_at: "2021-07-09 15:32:48">, #<Post id: 2, title: nil, created_at: "2021-07-09 15:33:50", updated_at: "2021-07-09 15:33:50">, #<Post id: 3, title: nil, created_at: "2021-07-09 15:33:55", updated_at: "2021-07-09 15:33:55">, #<Post id: 4, title: nil, created_at: "2021-07-09 15:33:57", updated_at: "2021-07-09 15:33:57">]>
Hope this is someway helpful. Please post if any comments are there, so I can clarify if I could. :)

PG::UndefinedTable: ERROR: missing FROM-clause entry for table "Teams"

I get the following error when trying to order a query by an associated table's "name" attribute.
Error
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "team"
Query
: SELECT "team_seasons"."id" AS t0_r0, "team_seasons"."season_id" AS t0_r1, "team_seasons"."team_id" AS t0_r2, "team_seasons"."created_at" AS t0_r3, "team_seasons"."updated_at" AS t0_r4, "team_seasons"."points" AS t0_r5, "team_seasons"."goals_for" AS t0_r6, "team_seasons"."goals_against" AS t0_r7, "team_seasons"."games_played" AS t0_r8, "teams"."id" AS t1_r0, "teams"."name" AS t1_r1, "teams"."city" AS t1_r2, "teams"."created_at" AS t1_r3, "teams"."updated_at" AS t1_r4 FROM "team_seasons" LEFT OUTER JOIN "teams" ON "teams"."id" = "team_seasons"."team_id" WHERE "team_seasons"."season_id" = 1 ORDER BY team.name
SeasonsController.rb
class SeasonsController < ApplicationController
load_and_authorize_resource
def show
#season = Season.find(params[:id])
#teamseasons = TeamSeason.where(season: #season).includes(:team).order("team.name")
end
Removing the order or ordering by an attribute on the teamseason record doesn't produce the error so I know it's something related to the ordering of the related record. I thought including it was all I needed to do but obviously it's not working. Any help is much appreciated.
Try changing team.name to teams.name in (mind s)
TeamSeason.where(season: #season).includes(:team).order("team.name")

For the sake of efficiency and optimization, should I use eager_load or includes?

Currently, my code reads like this:
current_user.association.includes(a: [:b, {c: :d}, {e: :f}]).to_a
When doing a call, it seems every single includes is called through its own SELECT call to the DB.
However, when I do current_user.association.eager_load(a: [:b, {c: :d}, {e: :f}]).to_a I see one huge SELECT call.
I ask because I haven't seen this raised before. I would assume that the eager_load is more efficient due to less DB calls.
As I can't infer the query from your description (a: [:b, {c: :d}, {e: :f}]), I need to talk about includes for a little bit.
includes is a query method which accommodates in different situations.
Here are some example code:
# model and reference
class Blog < ActiveRecord::Base
has_many :posts
# t.string "name"
# t.string "author"
end
class Post < ActiveRecord::Base
belongs_to :blog
# t.string "title"
end
# seed
(1..3).each do |b_id|
blog = Blog.create(name: "Blog #{b_id}", author: 'someone')
(1..5).each { |p_id| blog.posts.create(title: "Post #{b_id}-#{p_id}") }
end
In one case, it fires two separate queries, just like preload.
> Blog.includes(:posts)
Blog Load (2.8ms) SELECT "blogs".* FROM "blogs"
Post Load (0.7ms) SELECT "posts".* FROM "posts" WHERE "posts"."blog_id" IN (1, 2, 3)
In another case, when querying on the referenced table, it fires only one LEFT OUTER JOIN query, just like eager_load.
> Blog.includes(:posts).where(posts: {title: 'Post 1-1'})
SQL (0.3ms) SELECT "blogs"."id" AS t0_r0, "blogs"."name" AS t0_r1, "blogs"."author" AS t0_r2, "blogs"."created_at" AS t0_r3, "blogs"."updated_at" AS t0_r4, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."created_at" AS t1_r2, "posts"."updated_at" AS t1_r3, "posts"."blog_id" AS t1_r4 FROM "blogs" LEFT OUTER JOIN "posts" ON "posts"."blog_id" = "blogs"."id" WHERE "posts"."title" = ? [["title", "Post 1-1"]]
So, I think you may asking for the different part of includes and eager_load, which is
Should we use two separate queries or one LEFT OUTER JOIN query for the sake of efficiency and optimisation?
This also confuses me. After some digging, I've found this article by Fabio Akita convinced me. Here are some references and example:
For some situations, the monster outer join becomes slower than many smaller queries. The bottom line is: generally it seems better to split a monster join into smaller ones. This avoid the cartesian product overload problem.
The longer and more complex the result set, the more this matters because the more objects Rails would have to deal with. Allocating and deallocating several hundreds or thousands of small duplicated objects is never a good deal.
Example for query data from Rails
> Blog.eager_load(:posts).map(&:name).count
SQL (0.9ms) SELECT "blogs"."id" AS t0_r0, "blogs"."name" AS t0_r1, "blogs"."author" AS t0_r2, "blogs"."created_at" AS t0_r3, "blogs"."updated_at" AS t0_r4, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."created_at" AS t1_r2, "posts"."updated_at" AS t1_r3, "posts"."blog_id" AS t1_r4 FROM "blogs" LEFT OUTER JOIN "posts" ON "posts"."blog_id" = "blogs"."id"
=> 3
Example for SQL data returned from LEFT OUTER JOIN query
sqlite> SELECT "blogs"."id" AS t0_r0, "blogs"."name" AS t0_r1, "blogs"."author" AS t0_r2, "blogs"."created_at" AS t0_r3, "blogs"."updated_at" AS t0_r4, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."created_at" AS t1_r2, "posts"."updated_at" AS t1_r3, "posts"."blog_id" AS t1_r4 FROM "blogs" LEFT OUTER JOIN "posts" ON "posts"."blog_id" = "blogs"."id";
1|Blog 1|someone|2015-11-11 15:22:35.015095|2015-11-11 15:22:35.015095|1|Post 1-1|2015-11-11 15:22:35.053689|2015-11-11 15:22:35.053689|1
1|Blog 1|someone|2015-11-11 15:22:35.015095|2015-11-11 15:22:35.015095|2|Post 1-2|2015-11-11 15:22:35.058113|2015-11-11 15:22:35.058113|1
1|Blog 1|someone|2015-11-11 15:22:35.015095|2015-11-11 15:22:35.015095|3|Post 1-3|2015-11-11 15:22:35.062776|2015-11-11 15:22:35.062776|1
1|Blog 1|someone|2015-11-11 15:22:35.015095|2015-11-11 15:22:35.015095|4|Post 1-4|2015-11-11 15:22:35.065994|2015-11-11 15:22:35.065994|1
1|Blog 1|someone|2015-11-11 15:22:35.015095|2015-11-11 15:22:35.015095|5|Post 1-5|2015-11-11 15:22:35.069632|2015-11-11 15:22:35.069632|1
2|Blog 2|someone|2015-11-11 15:22:35.072871|2015-11-11 15:22:35.072871|6|Post 2-1|2015-11-11 15:22:35.078644|2015-11-11 15:22:35.078644|2
2|Blog 2|someone|2015-11-11 15:22:35.072871|2015-11-11 15:22:35.072871|7|Post 2-2|2015-11-11 15:22:35.081845|2015-11-11 15:22:35.081845|2
2|Blog 2|someone|2015-11-11 15:22:35.072871|2015-11-11 15:22:35.072871|8|Post 2-3|2015-11-11 15:22:35.084888|2015-11-11 15:22:35.084888|2
2|Blog 2|someone|2015-11-11 15:22:35.072871|2015-11-11 15:22:35.072871|9|Post 2-4|2015-11-11 15:22:35.087778|2015-11-11 15:22:35.087778|2
2|Blog 2|someone|2015-11-11 15:22:35.072871|2015-11-11 15:22:35.072871|10|Post 2-5|2015-11-11 15:22:35.090781|2015-11-11 15:22:35.090781|2
3|Blog 3|someone|2015-11-11 15:22:35.093902|2015-11-11 15:22:35.093902|11|Post 3-1|2015-11-11 15:22:35.097479|2015-11-11 15:22:35.097479|3
3|Blog 3|someone|2015-11-11 15:22:35.093902|2015-11-11 15:22:35.093902|12|Post 3-2|2015-11-11 15:22:35.103512|2015-11-11 15:22:35.103512|3
3|Blog 3|someone|2015-11-11 15:22:35.093902|2015-11-11 15:22:35.093902|13|Post 3-3|2015-11-11 15:22:35.108775|2015-11-11 15:22:35.108775|3
3|Blog 3|someone|2015-11-11 15:22:35.093902|2015-11-11 15:22:35.093902|14|Post 3-4|2015-11-11 15:22:35.112654|2015-11-11 15:22:35.112654|3
3|Blog 3|someone|2015-11-11 15:22:35.093902|2015-11-11 15:22:35.093902|15|Post 3-5|2015-11-11 15:22:35.117601|2015-11-11 15:22:35.117601|3
We got the expected result from Rails, but bigger result from SQL. And that's the efficiency lose for the LEFT OUTER JOIN.
So my conclusion is, prefer includes over eager_load.
I've concluded a blog post about Preload, Eager_load, Includes, References, and Joins in Rails while researching. Hope this can help.
Reference
Remove N+1 queries in your Ruby on Rails app
Rails :include vs. :joins
Preload, Eagerload, Includes and Joins
Rolling with Rails 2.1 - The First Full Tutorial - Part 2
So, as it turns out, at one point ActiveRecord actually attempted to get everything into one query, but then opted it wasn't such a good idea.
I explored this with my query above and 4000 records.
A quick analysis:
eager_load took 2,600 milliseconds.
includes took 72 milliseconds.
eager_load took 36 times as long as includes.

searching by email in ActiveRecord using named scope "<field> is ambiguous'

Using rails 3.2.6.
# 1 letter domain name in email without scope
> Member.where('UPPER(email) LIKE UPPER(?)' , "a#b.com")
Member Load (0.7ms) SELECT "members".* FROM "members" WHERE (UPPER(email) LIKE UPPER('a#b.com'))
=> []
# 2 letter domain name in email without scope
> Member.where('UPPER(email) LIKE UPPER(?)' , "a#bc.com")
Member Load (0.7ms) SELECT "members".* FROM "members" WHERE (UPPER(email) LIKE UPPER('a#bc.com'))
=> []
# 1 letter domain name in email with scope
> Member.with_households.where('UPPER(email) LIKE UPPER(?)' , "a#b.com")
Member Load (0.7ms) SELECT "members".* FROM "members" WHERE (UPPER(email) LIKE UPPER('a#b.com'))
=> []
# 2 letter domain name in email with scope
> Member.with_households.where('UPPER(email) LIKE UPPER(?)' , "a#bs.com")
SQL (0.6ms) SELECT "members"."id" AS t0_r0, "members"."last_name" AS t0_r1, "members"."first_name" AS t0_r2, "members"."household_id" AS t0_r3, "members"."created_at" AS t0_r4, "members"."updated_at" AS t0_r5, "members"."phone1" AS t0_r6, "members"."phone2" AS t0_r
7, "members"."address1" AS t0_r8, "members"."address2" AS t0_r9, "members"."city" AS t0_r10, "members"."state" AS t0_r11, "members"."zip" AS t0_r12, "members"."notes" AS t0_r13, "members"."active" AS t0_r14, "members"."email" AS t0_r15, "households"."id" AS t1_r0, "ho
useholds"."balance" AS t1_r1, "households"."created_at" AS t1_r2, "households"."updated_at" AS t1_r3, "households"."notes" AS t1_r4, "members_households"."id" AS t2_r0, "members_households"."last_name" AS t2_r1, "members_households"."first_name" AS t2_r2, "members_hou
seholds"."household_id" AS t2_r3, "members_households"."created_at" AS t2_r4, "members_households"."updated_at" AS t2_r5, "members_households"."phone1" AS t2_r6, "members_households"."phone2" AS t2_r7, "members_households"."address1" AS t2_r8, "members_households"."ad
dress2" AS t2_r9, "members_households"."city" AS t2_r10, "members_households"."state" AS t2_r11, "members_households"."zip" AS t2_r12, "members_households"."notes" AS t2_r13, "members_households"."active" AS t2_r14, "members_households"."email" AS t2_r15 FROM "members
" LEFT OUTER JOIN "households" ON "households"."id" = "members"."household_id" LEFT OUTER JOIN "members" "members_households" ON "members_households"."household_id" = "households"."id" WHERE (UPPER(email) LIKE UPPER('a#bs.com'))
ActiveRecord::StatementInvalid: PGError: ERROR: column reference "email" is ambiguous
LINE 1: ..."."household_id" = "households"."id" WHERE (UPPER(email) LIK...
Here's the error:
ActiveRecord::StatementInvalid: PGError: ERROR: column reference "email" is ambiguous
A Household has_many Members.
Here's the with_households scope definition:
scope :with_households, :include => [{:household => :members}]
The email domain length may be a red herring, but I couldn't reproduce the error otherwise. Why is Arel doing a bunch of joins in just this case?
Try
Member.with_households.where('UPPER(members.email) LIKE UPPER(?)' , "a#bs.com")
ActiveRecord StatementInvalid is ambiguous is ARs way of saying: Mister, your SQL statement does not make sense because a field you are examining is found on several tables and I don't know which to use.
I'm guessing the with_households scope looks at another table which also has an email field. Or maybe you have a default_scope which does the same. Try specifying the table name everywhere, e.g. members.email and managers.email.
Member.with_households.where(Member.arel_table[:email].matches("a#bs.com"))

Resources