I have a situation in my Rails 4 app, where I have STI and want to customize the default queries by additional type
.
Classes:
class Candidate < ApplicationRecord
end
class Candidate::Site < Candidate
end
Now, if I make query, I get results as follow:
> Candidate::Site.count
# SELECT COUNT(*) FROM "candidates" WHERE "candidates"."type" IN ('Candidate::Site')
=> 0
Now, in my situation, I want to add an additional type
which query should look for every time. By leveraging the IN
clause, my expected query to be fired is:
SELECT COUNT(*) FROM "candidates" WHERE "candidates"."type" IN ('Candidate::Site', 'Site')
Can someone help me out to control this IN
clause here? Thanks in advance.
After detailed research and diving deep into the Rails STI source code, I found that my scenario will need to override the Rails' default STI. Following is what I needed to achieve the goal:
class Candidate::Site
# To enable renaming of Site to Candidate::Site
# per ENG-9551, we need to:
# 1. disable the 'type' column from using Rails' built-in STI
self.inheritance_column = :_nonexistant_column_to_bypass_sti
# 2. manually set the type column to Candidate::Site when we save,
# so that new and edited records are saved as Candidate::Site
before_save { self.type = 'Candidate::Site' }
# 3. always report the type as a Candidate::Site
def type
'Candidate::Site'
end
# 4. and set a default scope which only reads type columns that are
# 'Candidate::Site' or 'Site' so that STI
# still appears to be the same as always
default_scope { where(type: 'Candidate::Site').or(where(type: 'Site')) }
...
...
...
end
So, now any new record created with Candidate::Site.create
will store type Candidate::Site
while queries will use default scope and consider both the type, Candidate::Site
as well as Site
.