I implemented STI to separate 2 types of Skill objects: DefinedSkill and DeployedSkill. They are physically very close, but are managed different ways.
One method of the DefinedSkill is the deploy method, which creates a nearly identical DeployedSkill.
Initially, I wrote this:
def deploy
@template_skill = DefinedSkill.find(params[:id])
if @template_skill.status.code == "ACCEPTED"
@deployed_skill = @template_skill.deep_clone include: [:translations]
@deployed_skill.type = 'DeployedSkill'
---
@deployed_skill.save
end
end
But this produces an object of DefinedSkill class, even though I try to assign the type attribute.
Then I tried to work at attributes level, and wrote this:
def deploy
@template_skill = DefinedSkill.find(params[:id])
if @template_skill.status.code == "ACCEPTED"
@deployed_skill = DeployedSkill.new(@template_skill.attributes.except(:id, :type))
# @deployed_skill.type = 'DeployedSkill' (useless as type is managed by STI feature)
---
@deployed_skill.save
end
end
But this produces the following error:
ActiveRecord::SubclassNotFound (Invalid single-table inheritance type: DefinedSkill is not a subclass of DeployedSkill)
So this is my question: how can I create an object of a sibling class in the context of STI?
Many thanks to msencenb and felipeecst for putting me on the way. After reading the doc and trying, I came to the conclusion that the existing object could not be converted, but class conversion should be done when creating the new instance.
The solution I applied is:
@deployed_skill = @template_skill.becomes!(DeployedSkill).deep_clone include: [:translations]
which solved my issue.