Empty Scope with Ruby on Rails
Asked Answered
H

7

19

Following Problem:
I need something like an empty scope. Which means that this scope is emtpy, but responds to all methods a scope usually responds to. I'm currently using a little dirty hack. I simply supply "1=0" as conditions. I find this realy ugly, since it hits the database. Simply returning an empty array won't work, since the result must respond to the scoped methods.

Is there a better existing solution for this or will I need to code this myself?

Maybe some example code could help explain what i need:


class User < ActiveRecord::Base
  named_scope :admins, :conditions => {:admin => true }
  named_scope :none_dirty, :conditions => "1=0" # this scope is always empty

  def none_broken
    []
  end

  def self.sum_score # okay, a bit simple, but a method like this should work!
    total = 0
    self.all.each do |user|
      total += user.score
    end
    return total
  end
end
User.admin.sum_score # the score i want to know
User.none_drity.sum_score # works, but hits the db
User.none_broken.sum_score # ...error, since it doesn't respond to sum_score
Hemianopsia answered 17/9, 2010 at 13:45 Comment(3)
Why would the score of an empty set ever be anything other than 0? What are you trying to accomplish here?Provencher
You are looking for an empty collection.Myles
@jdl: it wouldn't be something other than 0.Hemianopsia
H
0

The thing you are looking for does not exist. You could implement something like this by monky patching the find method. Yet, this would be an overkill, so I recomend keeping this unless it's performance critical.

Hemianopsia answered 13/11, 2010 at 20:1 Comment(0)
A
26

Rails 4 introduces the none scope.

It is to be used in instances where you have a method which returns a relation, but there is a condition in which you do not want the database to be queried.

If you want a scope to return an unaltered scope use all:

No longer will a call to Model.all execute a query immediately and return an array of records. In Rails 4, calls to Model.all is equivalent to now deprecated Model.scoped. This means that more relations can be chained to Model.all and the result will be lazily evaluated.

Aswarm answered 11/4, 2014 at 13:1 Comment(0)
M
11
User.where('false')

returns an ActiveRecord::Relation with zero elements, that is a chain-able scope that won't hit the database until you actually try to access one of its elements. This is similar to PhilT's solution with ('1=0') but a little more elegant.

Melan answered 7/2, 2013 at 13:30 Comment(0)
N
2

Sorry User.scoped is not what you want. As commented this returns everything. Should have paid more attention to the question.

I've seen where('1 = 0') suggested before and Rails should probably cache it as well.

Also, where('1 = 0') won't hit the database until you do .all, .each, or one of the calculations methods.

Nitrification answered 18/11, 2011 at 15:37 Comment(1)
User.scoped returns all users, so it's not really an "empty" scope. I think he means an empty scope that would return no users. Sort of equivalent to [] but a scope.Gothic
J
0

I thing you need User.scoped({})

Judijudicable answered 17/9, 2010 at 14:11 Comment(2)
Wouldn't User.scoped({}) be equivalent to User.all?Myles
@Swanand: they are not equivalent, scoped returns a lazy ActiveRecord::NamedScope::Scope while User.all returns an array.Melbourne
H
0

The thing you are looking for does not exist. You could implement something like this by monky patching the find method. Yet, this would be an overkill, so I recomend keeping this unless it's performance critical.

Hemianopsia answered 13/11, 2010 at 20:1 Comment(0)
G
0

How about User.where(id: nil) ?

Or User.where(_id: nil) for mongoid.

Gothic answered 20/8, 2012 at 10:4 Comment(1)
That will still hit the database and it's not reliable (It's possible to have a record with a null id field especially legacy, non Rails databases).Nitrification
N
-1

Looking at your example code indicates you may not know about aggregated queries in SQL which are exposed as calculations methods in Rails:

User.sum(:score) will give you the sum of all users' scores

Take a look at Rails Guides for more info:

http://guides.rubyonrails.org/active_record_querying.html#sum

Nitrification answered 20/11, 2012 at 20:35 Comment(1)
Ehm, no, the sum was just an example as stated aboveHemianopsia

© 2022 - 2024 — McMap. All rights reserved.