Реализация STI в Ruby on Rails, как я могу дублировать объект из одного класса в другой?

#ruby-on-rails #activerecord #sti

#ruby-on-rails #activerecord #sti

Вопрос:

Я реализовал STI для разделения 2 типов объектов навыков: DefinedSkill и DeployedSkill. Они физически очень близки, но управляются по-разному.

Одним из методов DefinedSkill является метод deploy , который создает почти идентичный DeployedSkill .

Изначально я написал это:

 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
  

Но это создает объект класса DefinedSkill, хотя я пытаюсь присвоить атрибут type .

Затем я попытался работать на уровне атрибутов и написал это:

 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
  

Но это приводит к следующей ошибке:

 ActiveRecord::SubclassNotFound (Invalid single-table inheritance type: DefinedSkill is not a subclass of DeployedSkill)
  

Итак, это мой вопрос: как я могу создать объект родственного класса в контексте STI?

Комментарии:

1. В первом примере у него все еще есть класс DefinedSkill даже после перезагрузки объекта?

2. Становится! метод также может быть полезен: apidock.com/rails/ActiveRecord/Persistence/becomes!

Ответ №1:

Вместо настройки @deployed_skill = type попробуйте использовать becomes метод:

 @deployed_skill.becomes(DeployedSkill)
  

Ответ №2:

Большое спасибо msencenb и felipeecst за то, что указали мне путь. Прочитав документ и попробовав, я пришел к выводу, что существующий объект не может быть преобразован, но преобразование класса должно быть выполнено при создании нового экземпляра.

Решение, которое я применил, это:

 @deployed_skill = @template_skill.becomes!(DeployedSkill).deep_clone include: [:translations]
  

что решило мою проблему.