Returning `self` at ActiveRecord class method loses indirect reference

1.2k Views Asked by At

When defining a class method at an ActiveRecord, if I return self, the indirect reference is lost.

I'm not sure if I am using the right vocabulary, as I am just learning Ruby on Rails, so here is an example:

class User < ActiveRecord::Base
  has_many :orchids
end

class Orchid < ActiveRecord::Base
  belongs_to :user

  def self.search(query)
    if query.present?
      query = '%' + query.gsub(/\s+/, '%') + '%'
      where 'gender ILIKE :query OR variety ILIKE :query', query: query
    else
      # Problematic line:
      self
    end
  end
end

Using the above definition, this is what happens:

% User.last.orchids.count
   (0.8ms)  SELECT COUNT(*) FROM "orchids" WHERE "orchids"."user_id" = $1  [["user_id", 2]]
 => 0 

% User.last.orchids.search('').count
   (1.2ms)  SELECT COUNT(*) FROM "orchids"
 => 449 

% User.last.orchids.search('cat').count
   (1.2ms)  SELECT COUNT(*) FROM "orchids" WHERE "orchids"."user_id" = $1 AND (gender ILIKE '%cat%' OR variety ILIKE '%cat%')  [["user_id", 2]]
 => 0

So, returning self seems to make the indirect scope of "only the orchids of this user" go away. Returning self there means I'm returning the Orchid class instead of the ActiveRecord::Relation?

Reading a bit at the internet, I did find about scopes and why I should use them. Scopes do work the way I expect and I am using them now. I just do not get why this behaves like this when using class method definitions.

1

There are 1 best solutions below

0
On

Self will return the class because self is the class. As scope returns an ActiveRecord::Relation instance. So the Orchid.where method builds and returns a new ActiveRecord::Relation whereas the self will just return the class itself.

Both can still be chained with additional scopes should you choose. If you really want an AR::Relation back, change self to Orchid.none.