I'm new to Rails and I have strange problem.
Here is a code example:
class News < ActiveRecord::Base
scope :pinned, -> { where(pinned: true).first }
end
If there are records with "pinned" flag there is no problem, when I call News.pinned
returns a single record.
And I see this query in the log:
SELECT `news`.*
FROM `news`
WHERE `news`.`pinned` = 1
ORDER BY `news`.`id` ASC
LIMIT 1
But if there are no records with "pinned" flag, when I call News.pinned
the next two queries are executed:
SELECT `news`.*
FROM `news`
WHERE `news`.`pinned` = 1
ORDER BY `news`.`id` ASC
LIMIT 1
SELECT `news`.* FROM `news`
Thanks!
Friendy, here is the method "scope" of the ActiveRecord:
1 # File activerecord/lib/active_record/scoping/named.rb, line 145
2 def scope(name, body, &block)
3 extension = Module.new(&block) if block
4
5 # Check body.is_a?(Relation) to prevent the relation actually being
6 # loaded by respond_to?
7 if body.is_a?(Relation) || !body.respond_to?(:call)
8 ActiveSupport::Deprecation.warn(
9 "Using #scope without passing a callable object is deprecated. For " "example `scope :red, where(color: 'red')` should be changed to " "` scope :red, -> { where(color: 'red') }`. There are numerous gotchas " "in the former usage and it makes the implementation more complicated " "and buggy. (If you prefer, you can just define a class method named " "`self.red`.)"
10 )
11 end
12
13 singleton_class.send(:define_method, name) do |*args|
14 if body.respond_to?(:call)
15 scope = all.scoping { body.call(*args) }
16 scope = scope.extending(extension) if extension
17 else
18 scope = body
19 end
20
21 scope || all
22 end
23 end
Note the line 21 if the scope is "nil" then "all" is returned.
In your case, when you call "News.pinned" without records in line 15 the first consult is run and scope receive "nil", so when it gets to line 21, as scope is "nil", "all" is run making the second consult and returning all registers.
I've tested it overwriting the method "scope" by removing the "all" of the line 21 and i had just one query
To bypass this use:
class News < ActiveRecord::Base
def self.pinned
where(pinned: true).first
end
end
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