find_by inside a scope is firing 2 queries
Asked Answered
S

3

11

I am using Rails 4.2.3 and ruby 2.2.1

I have written a scope in roles model as follows:

app/models/role.rb

scope :default, -> { find_by(default: true) }

Now when I run

> Role.default

#this is the output I got.

Role Load (0.1ms)  SELECT  `roles`.* FROM `roles` WHERE `roles`.`default` = 1 LIMIT 1 
Role Load (0.1ms)  SELECT `roles`.* FROM `roles`
=> []

As you can see this fires 2 queries and returns wrong result.

I tried with class method instead of scope

def self.default
  self.find_by(default: true)
end

Now when I run

Role.default

#this is the output I got

Role Load (0.2ms)  SELECT  `roles`.* FROM `roles` WHERE `roles`.`default` = 1 LIMIT 1
=> nil

With class method find_by is working properly.

I am not able to understand what am I doing wrong here. Any help would be appreciated. Thanks in advance.

Style answered 9/7, 2015 at 22:44 Comment(0)
K
25

You shouldn't be using find_by inside a scope - find_by actually executes a database query.

You should only be using methods that return further scopes, for example where, limit, order and so on.

Katharina answered 9/7, 2015 at 23:19 Comment(1)
why? I remember I can do it(put find_by inside scope) before.Irs
H
4

ActiveRecord, the object relational mapping system built into Rails, provides you with a set of methods to use in your scopes to abstract out the database queries. Those methods are listed here:

http://guides.rubyonrails.org/active_record_querying.html#retrieving-objects-from-the-database

In your case, you will want to use the where query.

scope :default, -> { where(default: true) }

Hummingbird answered 10/7, 2015 at 2:24 Comment(0)
I
0

I ran into the same problem

at the beginning, I write my scope as

 scope :detect_by_keyword, ->(keyword) {
    find_by(normal_name: keyword)
  }

but it will query multiple times DB.

as the answer https://mcmap.net/q/963734/-find_by-inside-a-scope-is-firing-2-queries mentioned:

You shouldn't be using find_by inside a scope - find_by actually executes a database query.

You should only be using methods that return further scopes, for example where, limit, order and so on.

it works but I don't like it

  scope :detect_by_keyword, ->(keyword) {
    where(normal_name: keyword).limit(1)
  }

I have to do that like this MyClass.detect_by_keyword(keyword).first

if I put the .first inside the scope where(normal_name: keyword).limit(1).first, it will cause the same problem even when I'm using where(normal_name: keyword)[0]

So I turn it to Class method

it's my final solution:


  def self.detect_by_keyword(keyword)
    find_by(normal_name: keyword)
  end

by the way, I want to say: I've done this(put find_by into a scope`) before. there were not any problems. but recent project did. I guess it's the problem of Rails. Just Guess, but not sure 100 percent. Hope someone can give me proof.

Hope it helps you.

Irs answered 11/5, 2024 at 4:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.