Reputation: 3032
I has Model
that has_many
ModelItems
. ModelItems
belongs_to
OtherModel
which has a 'code' column.
I am looking to do something like this:
Model.find(1).model_items.includes(:other_model).order("other_model.code" :desc)
I am trying to sort based on the text of that related code column.
I have even tried:
ModelItems.where(model_id: 1).includes(:other_model).order("other_model.code" :desc)
I know I need an include or join here but no matter what I do I get a variation of this error:
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "other_model"
UPDATE
This is an example of not using the real model names bites you. I had it right all along.
The include was singular and the order model name needed to be plural - for clarity lets change other_model to widgit:
Model.find(1).model_items.includes(:widgit).order("widgits.code ASC")
Upvotes: 0
Views: 53
Reputation: 14910
Add references
ModelItems
.where(model_id: 1)
.includes(:other_model)
.references(:other_model)
.order("other_model.code DESC")
Upvotes: 1
Reputation: 29598
includes
in this context will execute 2 queries to create a pseudo outer join (also preload
) and is conceptually as follows
SELECT * FROM model_items WHERE model_items.model_id = 1
SELECT * FROM other_models WHERE other_models.model_item_id IN ( [IDS FROM PREVIOUS QUERY])
You can enforce single query execution in a few ways:
eager_load
- (ModelItems.eager_load(:other_model)
) This is how includes
works when you have the join table referenced in a hash finder query condition or when you add references
.
references
- (ModelItems.includes(:other_model).references(:other_model)
) This enforces the eager_load
path for include
where
Hash finder method (ModelItems.includes(:other_model).where(other_models: {name: 'ABC'})
) Here includes
intelligently realizes that you have placed a condition on the relationship with other_model
and will automatically create the join so that the query is not malformed. However this sort of query represents as an outer join but performs like an inner join which is less efficient *
However if you do not need the information in other_model
and just want to use this as a sort mechanism then you can use joins
(INNER JOIN) or left_joins
(OUTER JOIN) which will allow you to sort this data but will not retrieve the attributes or instantiate any related objects under the other_model
relationship
ModelItems.joins(:other_model)
# OR
ModelItems.left_joins(:other_model)
*These options can be combined as well as in the case of the includes
where
hash finder method I always recommend the following ModelItems.joins(:other_model).includes(:other_model).where(other_models: { name: 'ABC'})
(INNER JOIN). This will return the same data set as ModelItems.includes(:other_model).where(other_models: {name: 'ABC'})
(LEFT OUTER JOIN) however by utilizing an INNER JOIN it becomes more efficient than its LEFT OUTER JOIN
version
Sidenote order("other_models.code" :desc)
this is not valid. Instead you need to include the order direction in the String
or make that String
and Symbol
e.g. (("other_models.code DESC")
or ("other_models.code": :desc)
)
Upvotes: 1