Can't Join a model when using belongs_to - ruby-on-rails

class Exercise < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :exercises
end
Why can't I find all Exercises there were created by users with the role of "admin"?
Exercise.first :include => [:user], :conditions => ['user.role = "admin"']
The error shoes that the users table is not being joined.
Exercise.first :include => [:user], :conditions => ['user.role = "admin"']
Exercise Load Including Associations (0.0ms) Mysql::Error: Unknown column 'user.role' in 'where clause': SELECT `exercises`.`id` AS t0_r0, `exercises`.`title` AS t0_r1, `exercises`.`description` AS t0_r2, `exercises`.`fitness_type` AS t0_r3, `exercises`.`trackables` AS t0_r4, `exercises`.`user_id` AS t0_r5, `exercises`.`created_at` AS t0_r6, `exercises`.`updated_at` AS t0_r7, `users`.`id` AS t1_r0, `users`.`created_at` AS t1_r1, `users`.`updated_at` AS t1_r2, `users`.`first_name` AS t1_r3, `users`.`last_name` AS t1_r4, `users`.`email` AS t1_r5, `users`.`crypted_password` AS t1_r6, `users`.`password_salt` AS t1_r7, `users`.`persistence_token` AS t1_r8, `users`.`single_access_token` AS t1_r9, `users`.`perishable_token` AS t1_r10, `users`.`login_count` AS t1_r11, `users`.`failed_login_count` AS t1_r12, `users`.`last_request_at` AS t1_r13, `users`.`current_login_at` AS t1_r14, `users`.`last_login_at` AS t1_r15, `users`.`current_login_ip` AS t1_r16, `users`.`last_login_ip` AS t1_r17, `users`.`role` AS t1_r18, `users`.`avatar_file_name` AS t1_r19, `users`.`avatar_content_type` AS t1_r20, `users`.`avatar_file_size` AS t1_r21, `users`.`avatar_updated_at` AS t1_r22 FROM `exercises` LEFT OUTER JOIN `users` ON `users`.id = `exercises`.user_id WHERE (user.role = "admin") LIMIT 1
ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'user.role' in 'where clause': SELECT `exercises`.`id` AS t0_r0, `exercises`.`title` AS t0_r1, `exercises`.`description` AS t0_r2, `exercises`.`fitness_type` AS t0_r3, `exercises`.`trackables` AS t0_r4, `exercises`.`user_id` AS t0_r5, `exercises`.`created_at` AS t0_r6, `exercises`.`updated_at` AS t0_r7, `users`.`id` AS t1_r0, `users`.`created_at` AS t1_r1, `users`.`updated_at` AS t1_r2, `users`.`first_name` AS t1_r3, `users`.`last_name` AS t1_r4, `users`.`email` AS t1_r5, `users`.`crypted_password` AS t1_r6, `users`.`password_salt` AS t1_r7, `users`.`persistence_token` AS t1_r8, `users`.`single_access_token` AS t1_r9, `users`.`perishable_token` AS t1_r10, `users`.`login_count` AS t1_r11, `users`.`failed_login_count` AS t1_r12, `users`.`last_request_at` AS t1_r13, `users`.`current_login_at` AS t1_r14, `users`.`last_login_at` AS t1_r15, `users`.`current_login_ip` AS t1_r16, `users`.`last_login_ip` AS t1_r17, `users`.`role` AS t1_r18, `users`.`avatar_file_name` AS t1_r19, `users`.`avatar_content_type` AS t1_r20, `users`.`avatar_file_size` AS t1_r21, `users`.`avatar_updated_at` AS t1_r22 FROM `exercises` LEFT OUTER JOIN `users` ON `users`.id = `exercises`.user_id WHERE (user.role = "admin") LIMIT 1
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract_adapter.rb:219:in `log'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/mysql_adapter.rb:323:in `execute'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/mysql_adapter.rb:608:in `select'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all_without_query_cache'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/query_cache.rb:62:in `select_all'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1617:in `select_all_rows'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1395:in `find_with_associations'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1393:in `catch'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1393:in `find_with_associations'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1546:in `find_every'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1505:in `find_initial'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:613:in `find'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:623:in `first'
from (irb):7
>>
I know I can do this in a 2 step process by first finding all admin users then find exercises by "user_id" but want to make this into a named_scope.

I am pretty sure it is
Exercise.first :include => [:user], :conditions => ['users.role = "admin"']
instead of
Exercise.first :include => [:user], :conditions => ['user.role = "admin"']

Your condition should have users as plural: users.role

Related

Rails ERROR: 'missing FROM-clause entry' when order through associated model

In my Rails 5 and Ruby 2.4 app I've got two models CaregiverAuthorization and Registrant:
# caregiver_authorization
class CaregiverAuthorization < ApplicationRecord
belongs_to :registrant
scope :pending, (-> { where(status: [statuses[:pending], statuses[:pending_renewal]]) })
end
# registrant
class Registrant < User
has_many :caregiver_authorizations,
(-> { order('created_at asc') })
def full_name
[first_name, last_name].join(' ')
end
end
Now I want to have all pending caregiver_authorizations ordered by registrant.full_name. Pretty simple, so I did:
CaregiverAuthorization.includes(:registrant).order("registrants.full_name")
Surprisingly I got below error:
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "registrants"
LINE 1: ...id" AND "users"."type" IN ('Registrant') ORDER BY registrant...
^
What did I missed?
[Edit]
Full error message:
SQL (0.8ms) SELECT "caregiver_authorizations"."id" AS t0_r0, "caregiver_authorizations"."registrant_id" AS t0_r1, "caregiver_authorizations"."reviewer_id" AS t0_r2, "caregiver_authorizations"."reviewed_at" AS t0_r3, "caregiver_authorizations"."status" AS t0_r4, "caregiver_authorizations"."created_at" AS t0_r5, "caregiver_authorizations"."updated_at" AS t0_r6, "users"."id" AS t1_r0, "users"."external_system_id" AS t1_r1, "users"."external_system_type" AS t1_r2, "users"."type" AS t1_r3, "users"."login_id" AS t1_r4, "users"."first_name" AS t1_r5, "users"."last_name" AS t1_r6, "users"."status" AS t1_r7, "users"."minor" AS t1_r8, "users"."created_at" AS t1_r9, "users"."updated_at" AS t1_r10, "users"."paper_entry" AS t1_r11, "users"."date_of_birth" AS t1_r12, "users"."caregiver_limit_override" AS t1_r13, "users"."patient_limit_override" AS t1_r14 FROM "caregiver_authorizations" LEFT OUTER JOIN "users" ON "users"."id" = "caregiver_authorizations"."registrant_id" AND "users"."type" IN ('Registrant') ORDER BY registrants.full_name
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "registrants"
LINE 1: ...id" AND "users"."type" IN ('Registrant') ORDER BY registrant...
^
: SELECT "caregiver_authorizations"."id" AS t0_r0, "caregiver_authorizations"."registrant_id" AS t0_r1, "caregiver_authorizations"."reviewer_id" AS t0_r2, "caregiver_authorizations"."reviewed_at" AS t0_r3, "caregiver_authorizations"."status" AS t0_r4, "caregiver_authorizations"."created_at" AS t0_r5, "caregiver_authorizations"."updated_at" AS t0_r6, "users"."id" AS t1_r0, "users"."external_system_id" AS t1_r1, "users"."external_system_type" AS t1_r2, "users"."type" AS t1_r3, "users"."login_id" AS t1_r4, "users"."first_name" AS t1_r5, "users"."last_name" AS t1_r6, "users"."status" AS t1_r7, "users"."minor" AS t1_r8, "users"."created_at" AS t1_r9, "users"."updated_at" AS t1_r10, "users"."paper_entry" AS t1_r11, "users"."date_of_birth" AS t1_r12, "users"."caregiver_limit_override" AS t1_r13, "users"."patient_limit_override" AS t1_r14 FROM "caregiver_authorizations" LEFT OUTER JOIN "users" ON "users"."id" = "caregiver_authorizations"."registrant_id" AND "users"."type" IN ('Registrant') ORDER BY registrants.full_name
Maybe this will be helpfully:
2.4.5 :065 > CaregiverAuthorization.includes(:registrant).order("registrants.full_name").to_sql
=> "SELECT \"caregiver_authorizations\".\"id\" AS t0_r0, \"caregiver_authorizations\".\"registrant_id\" AS t0_r1, \"caregiver_authorizations\".\"reviewer_id\" AS t0_r2, \"caregiver_authorizations\".\"reviewed_at\" AS t0_r3, \"caregiver_authorizations\".\"status\" AS t0_r4, \"caregiver_authorizations\".\"created_at\" AS t0_r5, \"caregiver_authorizations\".\"updated_at\" AS t0_r6, \"users\".\"id\" AS t1_r0, \"users\".\"external_system_id\" AS t1_r1, \"users\".\"external_system_type\" AS t1_r2, \"users\".\"type\" AS t1_r3, \"users\".\"login_id\" AS t1_r4, \"users\".\"first_name\" AS t1_r5, \"users\".\"last_name\" AS t1_r6, \"users\".\"status\" AS t1_r7, \"users\".\"minor\" AS t1_r8, \"users\".\"created_at\" AS t1_r9, \"users\".\"updated_at\" AS t1_r10, \"users\".\"paper_entry\" AS t1_r11, \"users\".\"date_of_birth\" AS t1_r12, \"users\".\"caregiver_limit_override\" AS t1_r13, \"users\".\"patient_limit_override\" AS t1_r14 FROM \"caregiver_authorizations\" LEFT OUTER JOIN \"users\" ON \"users\".\"id\" = \"caregiver_authorizations\".\"registrant_id\" AND \"users\".\"type\" IN ('Registrant') ORDER BY registrants.full_name"
Please note that includes does not necessarily join tables in the database query. It is built to avoid N+1 queries and it might happen that it simply runs two queries (one for the caregiver_authorizations and another for the associated registrants.
When you really need both tables in one query because you need to filter or order by them then you need to use joins. Additionally, the table is not named registrants but users because Registrant is a subclass of User. And you cannot order by full_name because full_name is not a database query but a method in your model. To order by full_name you need to simulate the behavior of that method in SQL.
I guess the following should work for you:
CaregiverAuthorization
.pending
.joins(:registrant)
.order(Arel.sql("LOWER(CONCAT(users.first_name, ' ', users.last_name))"))

How can I write an .includes() plus .where() on both top model and associated model in Rails4?

I didn't have any idea what was going wrong with this query:
#customers =
Customer.includes(:phone_numbers, :emails)
.select("first_name, last_name, zip_code, customers.id, street1, street2")
.where(:merchant_id => environment)
.where("phone_numbers.number ~* :key",
:key => key, :digits => digits)
It was working fine in Rails3.
I stumbled onto some documentation here that helped me resolve it in Rails4, but I'd like to know if there is a better way to write this query.
It produces the following (this is gnarly...):
"SELECT first_name, last_name, zip_code, customers.id, street1, street2, "customers"."id" AS t0_r0, "customers"."account_id" AS t0_r1, "customers"."first_name" AS t0_r2, "customers"."last_name" AS t0_r3, "customers"."street1" AS t0_r4, "customers"."street2" AS t0_r5, "customers"."city_id" AS t0_r6, "customers"."city" AS t0_r7, "customers"."state" AS t0_r8, "customers"."state_id" AS t0_r9, "customers"."zip_code" AS t0_r10, "customers"."country" AS t0_r11, "customers"."municipality" AS t0_r12, "customers"."latitude" AS t0_r13, "customers"."longitude" AS t0_r14, "customers"."location" AS t0_r15, "customers"."customer_type" AS t0_r16, "customers"."notes" AS t0_r17, "customers"."birthday" AS t0_r18, "customers"."merchant_id" AS t0_r19, "customers"."gmaps" AS t0_r20, "customers"."marketing" AS t0_r21, "customers"."communication_method" AS t0_r22, "customers"."account_status" AS t0_r23, "customers"."account_type" AS t0_r24, "customers"."created_at" AS t0_r25, "customers"."updated_at" AS t0_r26, "customers"."api_customer_id" AS t0_r27, "customers"."api_updated_at" AS t0_r28, "phone_numbers"."id" AS t1_r0, "phone_numbers"."customer_id" AS t1_r1, "phone_numbers"."account_id" AS t1_r2, "phone_numbers"."contact_id" AS t1_r3, "phone_numbers"."number" AS t1_r4, "phone_numbers"."country_code" AS t1_r5, "phone_numbers"."area_code" AS t1_r6, "phone_numbers"."extension" AS t1_r7, "phone_numbers"."created_at" AS t1_r8, "phone_numbers"."updated_at" AS t1_r9, "emails"."id" AS t2_r0, "emails"."customer_id" AS t2_r1, "emails"."account_id" AS t2_r2, "emails"."contact_id" AS t2_r3, "emails"."address" AS t2_r4, "emails"."created_at" AS t2_r5, "emails"."updated_at" AS t2_r6
FROM "customers"
LEFT OUTER JOIN "phone_numbers" ON "phone_numbers"."customer_id" = "customers"."id"
LEFT OUTER JOIN "emails" ON "emails"."customer_id" = "customers"."id"
WHERE "customers"."merchant_id" = 29 AND (phone_numbers.number ~* '424298')"
Since you aren't selecting any of the fields in phone_numbers or emails I think you want to use join not includes. Tricky bit is to make the LEFT OUTER work.
http://apidock.com/rails/v4.2.1/ActiveRecord/QueryMethods/joins
Something like this maybe.
Customer.
select("first_name, last_name, zip_code, customers.id, street1, street2").
joins("LEFT OUTER JOIN phone_numbers ON phone_numbers.customer_id = customers.id").
joins("LEFT OUTER JOIN emails ON emails.customer_id = customers.id").
where(:merchant_id => environment).
where("phone_numbers.number ~* :key", :key => key, :digits => digits)

ActiveRecord includes query

Products has Variants.
I'm trying to fetch Variants that has cost_currency: "USD"
A Variant may look like this:
Spree::Variant id: 22, cost_currency: "USD">
Spree::Product.includes('variants') returns a lot of Variants, but if I try to filter only the ones that has cost_currency = true it fails.
This is what I did:
2.2.3 :077 > Spree::Product.includes('variants')
.where( variants: { cost_currency: "USD" })
But that throws an ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: variants.cost_currency error, which I don't understand why.
Full stack trace:
SQL (0.5ms) SELECT "spree_products"."id" AS t0_r0, "spree_products"."name" AS t0_r1, "spree_products"."description"
AS t0_r2, "spree_products"."available_on" AS t0_r3, "spree_pro
ducts"."deleted_at" AS t0_r4, "spree_products"."slug" AS t0_r5, "spree_products"."meta_description" AS t0_r6, "spree_products"."meta_keywords" AS t0_r7, "spree_products"."tax_catego
ry_id" AS t0_r8, "spree_products"."shipping_category_id" AS t0_r9, "spree_products"."created_at" AS t0_r10, "spree_products"."updated_at" AS t0_r11, "spree_products"."promotionable"
AS t0_r12, "spree_products"."meta_title" AS t0_r13, "spree_variants"."id" AS t1_r0, "spree_variants"."sku" AS t1_r1, "spree_variants"."weight" AS t1_r2, "spree_variants"."height" A
S t1_r3, "spree_variants"."width" AS t1_r4, "spree_variants"."depth" AS t1_r5, "spree_variants"."deleted_at" AS t1_r6, "spree_variants"."is_master" AS t1_r7, "spree_variants"."produ
ct_id" AS t1_r8, "spree_variants"."cost_price" AS t1_r9, "spree_variants"."position" AS t1_r10, "spree_variants"."cost_currency" AS t1_r11, "spree_variants"."track_inventory" AS t1_
r12, "spree_variants"."tax_category_id" AS t1_r13, "spree_variants"."updated_at" AS t1_r14 FROM "spree_products" LEFT OUTER JOIN "spree_variants" ON "spree_variants"."product_id" =
"spree_products"."id" AND "spree_variants"."is_master" = ? AND "spree_variants"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND "variants"."cost_currency" = ?
[["is_master", "f"], ["cost_currency", "USD"]]
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: variants.cost_currency: SELECT "spree_products"."id" AS t0_r0, "spree_products"."name" AS t0_r1, "spree_produc
ts"."description" AS t0_r2, "spree_products"."available_on" AS t0_r3, "spree_products"."deleted_at" AS t0_r4, "spree_products"."slug" AS t0_r5, "spree_products"."meta_description" A
S t0_r6, "spree_products"."meta_keywords" AS t0_r7, "spree_products"."tax_category_id" AS t0_r8, "spree_products"."shipping_category_id" AS t0_r9, "spree_products"."created_at" AS t
0_r10, "spree_products"."updated_at" AS t0_r11, "spree_products"."promotionable" AS t0_r12, "spree_products"."meta_title" AS t0_r13, "spree_variants"."id" AS t1_r0, "spree_variants"
."sku" AS t1_r1, "spree_variants"."weight" AS t1_r2, "spree_variants"."height" AS t1_r3, "spree_variants"."width" AS t1_r4, "spree_variants"."depth" AS t1_r5, "spree_variants"."dele
ted_at" AS t1_r6, "spree_variants"."is_master" AS t1_r7, "spree_variants"."product_id" AS t1_r8, "spree_variants"."cost_price" AS t1_r9, "spree_variants"."position" AS t1_r10, "spre
e_variants"."cost_currency" AS t1_r11, "spree_variants"."track_inventory" AS t1_r12, "spree_variants"."tax_category_id" AS t1_r13, "spree_variants"."updated_at" AS t1_r14 FROM "spre
e_products" LEFT OUTER JOIN "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = ? AND "spree_variants"."deleted_at" IS NULL
WHERE "spree_products"."deleted_at" IS NULL AND "variants"."cost_currency" = ?
Please try doing
Spree::Product.includes(:variants).where('spree_variants.cost_currency = "USD"')
or
Spree::Product.includes('variants').where('spree_variants.cost_currency = "USD" ' )
or
Spree::Product.includes('variants').where(spree_variants: { cost_currency: 'USD' })

jruby rails4 eager_load doesn't work

I have two models:
class Transaction < ActiveRecord::Base
self.table_name = 'DEPOSIT_TRANSACTIONS'
belongs_to :deposit_account
scope :not_test, -> { includes(:deposit_account).where("deposit_accounts.is_test_account is null or deposit_accounts.is_test_account != 1").references(:deposit_account) }
...
end
class DepositAccount < ActiveRecord::Base
has_many :transactions, -> { order(:creation_date => :desc) }
default_scope { where(:purpose => 'COUNTERFEIT') }
scope :not_test, -> { where("is_test_account != 1") }
...
end
I tried to eager load the both tables with:
irb(main):008:0> request_transactions = Transaction.eager_load(:deposit_account)
**I polish the following output**
SQL (6390.0ms) SELECT "DEPOSIT_TRANSACTIONS"."ID" AS t0_r0,
"DEPOSIT_TRANSACTIONS"."DEPOSIT_ACCOUNT_ID" AS t0_r1,
"DEPOSIT_TRANSACTIONS"."TRANSACTION_TYPE" AS t0_r2,
"DEPOSIT_TRANSACTIONS"."TRACKING_ID" AS t0_r3,
"DEPOSIT_TRANSACTIONS"."AMOUNT" AS t0_r4,
"DEPOSIT_TRANSACTIONS"."STATUS" AS t0_r5,
"DEPOSIT_TRANSACTIONS"."TRANSACTION_COMMENT" AS t0_r6,
"DEPOSIT_TRANSACTIONS"."NOTIFICATION_EMAILS" AS t0_r7,
"DEPOSIT_TRANSACTIONS"."CREATED_BY" AS t0_r8,
"DEPOSIT_TRANSACTIONS"."CREATION_DATE" AS t0_r9,
"DEPOSIT_TRANSACTIONS"."LAST_UPDATED_BY" AS t0_r10,
"DEPOSIT_TRANSACTIONS"."LAST_UPDATED_DATE" AS t0_r11,
"DEPOSIT_TRANSACTIONS"."FINISH_DATE" AS t0_r12,
"DEPOSIT_TRANSACTIONS"."PAYMENT_DATE" AS t0_r13,
"DEPOSIT_TRANSACTIONS"."MATCH_TYPE" AS t0_r14,
"DEPOSIT_TRANSACTIONS"."ADDITIONAL_INFO" AS t0_r15,
"DEPOSIT_ACCOUNTS"."ID" AS t1_r0,
"DEPOSIT_ACCOUNTS"."SELLER_ID" AS t1_r1,
"DEPOSIT_ACCOUNTS"."MARKETPLACE_ID" AS t1_r2,
"DEPOSIT_ACCOUNTS"."PURPOSE" AS t1_r3,
"DEPOSIT_ACCOUNTS"."TOTAL_DEPOSIT_BALANCE" AS t1_r4,
"DEPOSIT_ACCOUNTS"."OUTSTANDING_DEPOSIT_REQUEST" AS t1_r5,
"DEPOSIT_ACCOUNTS"."OUTSTANDING_REFUND_REQUEST" AS t1_r6,
"DEPOSIT_ACCOUNTS"."CREATED_BY" AS t1_r7,
"DEPOSIT_ACCOUNTS"."CREATION_DATE" AS t1_r8,
"DEPOSIT_ACCOUNTS"."LAST_UPDATED_BY" AS t1_r9,
"DEPOSIT_ACCOUNTS"."LAST_UPDATED_DATE" AS t1_r10,
"DEPOSIT_ACCOUNTS"."IS_TEST_ACCOUNT" AS t1_r11,
"DEPOSIT_ACCOUNTS"."RECORD_VERSION_NUMBER" AS t1_r12,
"DEPOSIT_ACCOUNTS"."OUTSTANDING_CONFISCATE_REQUEST" AS t1_r13
FROM "DEPOSIT_TRANSACTIONS"
LEFT OUTER JOIN "DEPOSIT_ACCOUNTS"
ON "DEPOSIT_ACCOUNTS"."ID" = "DEPOSIT_TRANSACTIONS"."DEPOSIT_ACCOUNT_ID"
AND "DEPOSIT_ACCOUNTS"."PURPOSE" = 'COUNTERFEIT'
DepositAccount Load (235.0ms) SELECT "DEPOSIT_ACCOUNTS".* FROM "DEPOSIT_ACCOUNTS" WHERE "DEPOSIT_ACCOUNTS"."PURPOSE" = 'COUNTERFEIT' AND "DEPOSIT_ACCOUNTS"."ID" = 143 AND ROWNUM <= 1
DepositAccount Load (535.0ms) SELECT "DEPOSIT_ACCOUNTS".* FROM "DEPOSIT_ACCOUNTS" WHERE "DEPOSIT_ACCOUNTS"."PURPOSE" = 'COUNTERFEIT' AND "DEPOSIT_ACCOUNTS"."ID" = 143 AND ROWNUM <= 1
DepositAccount Load (471.0ms) SELECT "DEPOSIT_ACCOUNTS".* FROM "DEPOSIT_ACCOUNTS" WHERE "DEPOSIT_ACCOUNTS"."PURPOSE" = 'COUNTERFEIT' AND "DEPOSIT_ACCOUNTS"."ID" = 147 AND ROWNUM <= 1
DepositAccount Load (237.0ms) SELECT "DEPOSIT_ACCOUNTS".* FROM "DEPOSIT_ACCOUNTS" WHERE "DEPOSIT_ACCOUNTS"."PURPOSE" = 'COUNTERFEIT' AND "DEPOSIT_ACCOUNTS"."ID" = 138 AND ROWNUM <= 1
...
But it generates so many SQL, which means rails doesn't load eagerly I think. I expected the first clause is enough. Please help to eager load the tables. Thanks.
My environment:
jruby 1.7
rails 4.0
EDIT1:
I tried to run the same code on ruby 1.9 rails 4.0, the eager load works fine. So I guess this is caused by JRuby. Does anyone else have this problem?
Don't know if it matters, I use activerecord-oracle_enhanced-adapter in ruby 1.9 env, but JDBC driver in
JRuby. The database it oracle.
The problem is solved by upgrading activerecord from activerecord-4.0.9 to activerecord-4.1.5. BTW, I use activerecord-jdbc-adapter-1.3.7 as the adapter.

How to understand logic for advanced query in Ruby on Rails?

I have a user model
class User < ActiveRecord::Base
has_many :messages_received, :class_name=>"Message", :foreign_key=>'receiving_id', :conditions => {:message_type => "incoming"}
has_many :messages_sent, :class_name=>"Message", :foreign_key=>'sender_id', :conditions => {:message_type => "outgoing"}
end
Now I want to fetch all the users who havn't sent any messages in last 15 days so that I can notify them. I tried this but it's not working.
has_many :last_7_days_inactive_users, :class_name=>"Message", :foreign_key=>'receiving_id', :conditions =>{:messages_sent => ("created_at < ? " ,Time.now - 7.days)}
How can I amend this query?
Edit
User.last_7_days_inactive_users
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'users.messages_sent' in 'where clause': SELECT `users`.`id` AS t0_r0, `users`.`name` AS t0_r1, `users`.`email` AS t0_r2, `users`.`phone_number` AS t0_r3, `users`.`active` AS t0_r4, `users`.`created_at` AS t0_r5, `users`.`updated_at` AS t0_r6, `users`.`groups_count` AS t0_r7, `users`.`daily_sms_count` AS t0_r8, `users`.`new_user_sms_count` AS t0_r9, `users`.`source_type` AS t0_r10, `users`.`messages_count` AS t0_r11, `users`.`salt` AS t0_r12, `users`.`hashed_password` AS t0_r13, `users`.`verified_email` AS t0_r14, `users`.`email_verification_code` AS t0_r15, `users`.`auto_generated_password` AS t0_r16, `users`.`forgot_password_code_short` AS t0_r17, `users`.`forgot_password_code_long` AS t0_r18, `messages`.`id` AS t1_r0, `messages`.`body` AS t1_r1, `messages`.`sender_number` AS t1_r2, `messages`.`time_at` AS t1_r3, `messages`.`operator` AS t1_r4, `messages`.`circle` AS t1_r5, `messages`.`receiving_number` AS t1_r6, `messages`.`sender_id` AS t1_r7, `messages`.`system_phone_number_id` AS t1_r8, `messages`.`created_at` AS t1_r9, `messages`.`updated_at` AS t1_r10, `messages`.`message_type` AS t1_r11, `messages`.`parent_id` AS t1_r12, `messages`.`receiving_id` AS t1_r13, `messages`.`group_id` AS t1_r14, `messages`.`mp_hash` AS t1_r15, `messages`.`junk` AS t1_r16, `messages`.`command` AS t1_r17, `messages`.`message_size` AS t1_r18 FROM `users` LEFT OUTER JOIN `messages` ON `messages`.`sender_id` = `users`.`id` AND `messages`.`message_type` = 'incoming' WHERE `users`.`messages_sent` = 'messages_sent.created_at < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 7 DAY)'
It's very important to note that unless you use a Proc, your time will be evaluated once and once only and will represent a time locked in from the instant the class is loaded. In production mode this will persist for the life-time of the process which could be days if not months. This is probably not what you want.
Instead you may have better luck with declaring a scope on User and fetching them this way:
named_scope :last_7_days_inactive_users,
:include => :messages_sent,
:conditions => "messages.created_at < DATE_SUB(UTC_TIMESTAMP(), INTERVAL 7 DAY)"
For instance:
inactive_users = User.last_7_days_inactive_users.all
Edit: Updated the conditions expression to be direct, not a hash.

Resources