Вопрос

I am trying to get all the direct subclasses of a class that inherits from ActiveRecord::Base; that is, only classes that inherit directly from the base class, not subclasses of subclasses. But the normal way of doing this does not appear to work with ActiveRecord::Base subclasses.

Normally, this is done using the Class::subclasses method:

class C1; end
class C2 < C1; end
class C3 < C2; end
C1.subclasses
#=> [C2]

I want to do this for an ActiveRecord::Base subclass:

class T1 < ActiveRecord::Base; end
class T2 < T1; end
class T3 < T2; end
T1.subclasses
#=> [T2(Table doesn't exist), T3(Table doesn't exist)]

I get both the child and grandchild classes, which is not what I want! The same fundamental behavior occurs for classes that do have tables defined.

Already, this points out that ActiveRecord::Base subclasses act a little differently in that inspect() is overridden to provide the table name. So it's not too far a stretch to guess that they overrode subclasses as well.

  1. Is it possible to get a list only of the direct subclasses of an ActiveRecord::Base subclass?
  2. And why did they change subclasses()?
Это было полезно?

Решение

According to this:

http://apidock.com/rails/ActiveRecord/Base/subclasses/class

ActiveRecord::Base had a subclasses method that simply returned the value of descendants until version 3.1 (actually this says 3.0.9, but I think this is when it was deprecated; you can see it in the source code until 3.1). descendants returns everything that is < the receiver (the behavior you observed).

Here is the commit that removed it:

https://github.com/rails/rails/commit/9b610049bb4f73dbcdc670879683ec2a1a2ab780

Rails 3.1 and after should behave as you describe. If you are using Rails >= 3.1, then I'm not sure how to explain what you are seeing.

Другие советы

Reposted code from my comment above because comments don't allow good formatting. This works for my purposes:

class T1 < ActiveRecord::Base
  def self.my_subclasses
    Object.singleton_class.instance_method(:subclasses).bind(self).call
  end
end
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top