I’m struggling to understand why I’m unable to call .where
on the results of what looks to be an ActiveRecord query.
I’m dipping down into SQL a bit to create virtual columns for matching. We have two models: Organization
and Subscription
. My query to fetch orgs with subscriptions is as follows:
def orgs_with_plans
subquery = Subscription.select("DISTINCT ON (organization_id) *")
.order(:organization_id, created_at: :desc)
Organization
.joins("LEFT JOIN (#{subquery.to_sql}) AS subscription_data ON organizations.id = subscription_data.organization_id")
.select("
organizations.*,
(CASE
WHEN subscription_data.id IS NULL THEN
(CASE
WHEN organizations.trial_end_date > CURRENT_DATE THEN 'trial'
ELSE 'expired'
END)
ELSE subscription_data.plan_name
END) AS plan_name
")
end
I can successfully get plan_name
when I call the following:
orgs_with_plans.each do |org|
puts "orgname: #{org.name}, plan name: #{org.plan_name}"
end
Additionally, the output sql of orgs_with_plans.to_sql
runs as expected in my DB.
If I try to call orgs_with_plans.where('plan_name = ?', 'trial')
, I run into an error:
ActiveRecord::StatementInvalid:
PG::SyntaxError: ERROR: syntax error at or near "AS"
LINE 10: END) AS plan_name
Why is this invalid syntax when I use count
but totally fine otherwise?
2
Answers
The reason you are unable to directly call ActiveRecord methods like .count on the orgs_with_plans query result is because orgs_with_plans is not an array of records but an instance of ActiveRecord_Relation. However, you can still apply ActiveRecord methods to it by converting it into an array or by chaining the desired method at the end of the query.
To obtain the count of organizations with a specific plan name, you can modify your query as follows:
This will add a condition to the query to filter organizations with a plan name of ‘trial’ and then return the count.
Regarding the error you encountered when using .where(‘plan_name = ?’, ‘trial’), the issue is with the syntax of the SQL statement that gets generated. The subquery you are using in the LEFT JOIN clause has an aliased column named plan_name, which is causing the error. To resolve this, you can modify your query to use the column index instead of the alias in the WHERE clause:
In this modified query, the CASE statement is repeated in the WHERE clause, and the placeholders ? are used to pass the values ‘trial’, ‘expired’, and ‘trial’ respectively.
Remember to adjust the placeholders and values according to your specific use case.
By making these modifications, you should be able to use the .count method and apply additional conditions to your orgs_with_plans query result.
When you are referring to
plan_name
inside thewhere
, Rails is looking for a column namedplan_name
, which is not there. If you want to use the aliasplan_name
in thewhere
condition, you gonna needCTE
.You have to update your code a bit to make
orgs_with_plans.where('plan_name = ?', 'trial')
work:Or if you don’t want to use SQL, you could use
select
to filter outplan_name
s withtrial
Hope this helps!