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.
Related
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))"))
I am building a Rails app with a webpage that shows a list of QuoteDocuments sorted by the quotedocument's PDF created date, which is attached via ActiveStorage
class Quote < ApplicationRecord
has_many :quote_documents, dependent: :destroy
end
class QuoteDocument < ApplicationRecord
has_one_attached :document
end
This is the line of code I am using that gives me an error
#quote.quote_documents.includes(:document_attachment).order('active_storage_blobs.filename ASC')
And this is the error
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "active_storage_blobs")
And the SQL statement
: SELECT "quote_documents"."id" AS t0_r0, "quote_documents"."quote_id" AS t0_r1, "quote_documents"."version" AS t0_r2, "quote_documents"."created_at" AS t0_r3, "quote_documents"."updated_at" AS t0_r4, "quote_documents"."document_file_name" AS t0_r5, "quote_documents"."document_content_type" AS t0_r6, "quote_documents"."document_file_size" AS t0_r7, "quote_documents"."document_updated_at" AS t0_r8, "quote_documents"."document_type" AS t0_r9, "quote_documents"."description" AS t0_r10, "quote_documents"."user_id" AS t0_r11, "active_storage_attachments"."id" AS t1_r0, "active_storage_attachments"."name" AS t1_r1, "active_storage_attachments"."record_type" AS t1_r2, "active_storage_attachments"."record_id" AS t1_r3, "active_storage_attachments"."blob_id" AS t1_r4, "active_storage_attachments"."created_at" AS t1_r5 FROM "quote_documents" LEFT OUTER JOIN "active_storage_attachments" ON "active_storage_attachments"."record_id" = "quote_documents"."id" AND "active_storage_attachments"."record_type" = $1 AND "active_storage_attachments"."name" = $2 WHERE "quote_documents"."quote_id" = $3 AND "quote_documents"."document_type" = $4 ORDER BY active_storage_blobs.filename ASC LIMIT $5
Any idea what I should be doing to fix this?
You need to use include in your original statement that sets the #quote, rather than from the #quote variable:
#quote = Quote.includes(quote_documents: {document_attachment: :blob}).find(params[id])
in your controller
then in your view you should just be able to use:
#quote.quote_documents.order('active_storage_blobs.filename ASC')
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)
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' })
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.