Rails 3.1 and above has an awesome feature of prepared_statements. The basic idea behind prepared statements is to compile SQL statements once and cached for it future use. In other words - The benefit to prepared statements is that the database does not have to compile a query plan for every piece of SQL sent to it, potentially saving a lot of time.
Checkout an excellent blog(blog) to know more on prepared_statements.
Recently, I had to get raw sql from AR object so that I can pass it to EXPLAIN statement to get total number of rows (check this nice blog from Yogendra). As prepared_statements are enabled by default on PostgreSQL, I used to get following sql string:
SELECT "contacts"."id" FROM "contacts" WHERE "contacts"."user_id" = $1
In above query, the variable $1 was not replaced by actual id of user. On executing this query, I got exception:
ActiveRecord::StatementInvalid Exception: PG::UndefinedParameter: ERROR: there is no parameter $1
For this, I had to set prepared_statements flag in database.yml to false. But this will decrease performance of overall apTo solve this, I used unprepared_statement { .. }.
Contact.connection.unprepared_statement { @contacts.to_sql }
This gave me:
SELECT "contacts"."id" FROM "contacts" WHERE "contacts"."user_id" = "2"
This will not work if you have a query like this:
Contact.where("user_id IN (?)", current_user.account.users.select('id'))
Here, current_user.account.users.select('id') is a subquery. We need to unprepare the subquery separately to make whole query work with to_sql.
subquery = Contact.connection.unprepared_statement { current_user.account.users.select('id').to_sql } Contact.where("user_id IN (#{subquery})")