I'm trying to get data from a Postgresql table (table1
) filtered by a field (property
) of an other related table (table2
).
In pure SQL I would write the query like this:
SELECT * FROM table1 JOIN table2 USING(table2_id) WHERE table2.property LIKE 'query%'
This is working fine:
scope :my_scope, ->(query) { includes(:table2).where("table2.property": query) }
But what I really need is to filter with a LIKE operator rather than strict equality. However this is not working:
scope :my_scope, ->(query) { includes(:table2).where("table2.property LIKE ?", "#{query}%") }
As I am getting this error:
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "table2" LINE 1: ...ble2" WHERE "table1"."user_id" = $1 AND (tabl... ^ : SELECT "table1".* FROM "table1" WHERE "table1"."user_id" = $1 AND (table2.property LIKE 'query%') ORDER BY last_used_at DESC
What am I doing wrong here?
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.
You can avoid most n+1 queries in rails by simply eager loading associations. Eager loading allows you to load all of your associations (parent and children) once instead of n+1 times (which often happens with lazy loading, rails' default).
where returns an ActiveRecord::Relation (not an array, even though it behaves much like one), which is a collection of model objects. If nothing matches the conditions, it simply returns an empty relation. find (and its related dynamic find_by_columnname methods) returns a single model object.
.includes()
usually runs 2 separate queries unless it can find that your conditions forces a single LEFT OUTER JOIN
query, but it fails to do so in your case as the references are in a string (see this example).
You can force the single query behaviour by specifing .references(:table2)
:
scope :my_scope, ->(query) { includes(:table2)
.references(:table2)
.where("table2.property LIKE ?", "#{query}%") }
Or you can you can just use .eager_load()
:
scope :my_scope, ->(query) { eager_load(:table2)
.where("table2.property LIKE ?", "#{query}%") }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With