Reputation: 293
I'm a newer dev, and I want to know if I'm causing excessive queries with an index method.
The index method for my Ownerships model looks like this:
def index
@ownerships = Ownership.all.select { |t| t.player_id == nil}
Rails.application.config.counter = (Ownership.all.count - Ownership.all.select{ |t| t.player_id == nil}.count) + 1
end
It works fine. The goal is to set the counter equal to the id of the first Ownership that does not have a player assigned. But I'm concerned that I'm causing 3 separate queries every time the index action is called. Is that the case?
I know I can find the first record with 'nil' Player like this:
Ownership.all.select { |t| t.player_id == nil}.first(1)
Is there a simple way to set the counter equal to the ID of the record that is found?
Thank you.
Upvotes: 0
Views: 63
Reputation: 52357
Using Ruby in AR is inefficient and I suggest using it as a last resort.
Always try to get to the database layer.
The following AR query
Ownership.find_by(player_id: nil)
fires single SQL query:
SELECT `ownerships`.*
FROM `ownerships`
WHERE `ownerships`.`player_id` = NULL
LIMIT 1
and does exactly what you need.
Be aware, that with find_by
the following would result in NoMethodError
, if no record found
Ownership.find_by(player_id: nil).id
#=> NoMethodError: undefined method `id' for nil:NilClass
Take a look into finders docs for more info on AR querying.
Upvotes: 2
Reputation: 1159
You are selecting all existing Ownerships and then process them in Ruby - which is very inefficient. What if you got 10k Ownerships? Or 100k? Not only the query to database is too heavy, but also Ruby can exhaust the memory if collection is too big.
What you might want to do here is using SQL to find all needed records. In Rails, you can get SQL generated for you by ActiveRecord queries, like this:
@ownerships = Ownership.where(player_id: nil)
or
@ownership = Ownership.find_by(player_id: nil)
to find the first matching one.
Upvotes: 2