NothingToSeeHere
NothingToSeeHere

Reputation: 2363

Rails STI query all subclasses using base class

Imagine I have this STI table called living things with these such subclasses:

class LivingThing < ActiveRecord::Base
end

class Animal < LivingThing
end

class Plant < LivingThing
end

class Fungus < LivingThing
end

class Cat < Animal
end

class Dog < Animal
end

I am trying to get a very simple query of all records that INHERIT from subclass "Animal". So I want records wher type= "Cat" or type= "Dog". I don't know why I can't seem to figure this out.

none of these options work:

- animals = LivingThing.all.map{|r| r.kind_of?("Animal")}
- animals = LivingThing.all.map{|r| r.type == "Animal"}
- animals = LivingThing.kind_of?("Animal")

currently LivingThing.all =

 => #<ActiveRecord::Relation [#<Cat id: 2,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">, #<Dog id: 3,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">,#<Cat id: 4,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">, #<Cat id: 5,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">, #<Rose id: 6,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">, #<Oak id: 7,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">, #<Mushroom id: 6,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">, #<Ringworm id: 8,  status: 1,  created_at: "2016-03-25 00:57:20", updated_at: "2016-03-25 00:57:20">]> 

Upvotes: 2

Views: 3206

Answers (3)

Ben Yee
Ben Yee

Reputation: 1595

In case you are landing on this question and you're running and your ParentClass.all is not returning all of the subclass records... In Rails 6.0, the query not automatically return all subclasses.

You'll need to add the following in the parent class and specify each subclass that you would like to support:

require_dependency 'subclass_name'

See https://guides.rubyonrails.org/v6.0/autoloading_and_reloading_constants_classic_mode.html#autoloading-and-sti for more details

For Rails 7, a slightly different approach is recommended here: https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#single-table-inheritance

Upvotes: 2

Niels Kristian
Niels Kristian

Reputation: 8845

As of rails 4.2 (maybe even before), doing:

Animal.all will automatically render an sql call something like:

SELECT * FROM "living_things" WHERE "living_things"."type" IN ('Animal', 'Dog', 'Cat')

So there you have it. :-)

Upvotes: 1

K M Rakibul Islam
K M Rakibul Islam

Reputation: 34338

You can do this:

animals = LivingThing.all.map { |r| r if r.class.superclass.name == 'Animal' }

or:

animals = LivingThing.all.map { |r| r if r.class.superclass == Animal }

This should give you all the records of classes that are subclassed from the Animal class.

Upvotes: 1

Related Questions