带有rake任务和自定义STI名称的无效单表继承类型

时间:2017-08-30 17:21:28

标签: ruby-on-rails ruby-on-rails-4 activerecord rake rake-task

我做了很多工作,重构了大量代码,并对数据库模式进行了重大更改。现在我正在尝试编写一个rake任务来将记录从旧表迁移到新表。

我正在上课:

#app/models/restream/service.rb
class Restream::Service < ActiveRecord::Base
def self.types
    %w(custom multiple_destinations_service one_destination_service) +
    Restream::Custom.types + Restream::MultipleDestinationsService.types
  end

  def self.find_sti_class(type_name) #allows to find classes by short names
    type_name = "Restream::#{type_name.camelcase}".constantize
    super
  end
end

#app/models/restream/custom.rb
class Restream::Custom < Restream::Service
  def self.sti_name
    "custom"
  end

  def self.types
    %w(periscope odnoklassniki vkontakte)
  end
end

#app/models/restream/periscope.rb
class Restream::Periscope < Restream::Custom
  def self.sti_name
    "periscope"
  end
end

一切正常。直到我尝试手动添加记录。 在我之前的版本中,我有这样的结构:

class Restream::Custom < ActiveRecord::Base
  def self.types; %w(custom periscope vkontakte); end
end

class Restream::Periscope < Restream::Custom
  def self.sti_name; 'periscope'; end
end

现在我正在尝试从旧restream_custom表中获取所有记录,只需复制类型。大致是:

Restream::Custom.create(type: old_restream_custom.type)

那说不出来:

ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: periscope is not a subclass of Restream::Custom

显然不是!但无论如何我已经有了type: 'periscope'的一堆记录,所以我知道它是一个有效的值。 这是什么原因,我该如何解决这个问题?

==

我可以看到两种方式:

1)将type设为Restream::Periscope,而不仅仅是periscope。但是,这会创建Restream::Periscope.find_eachRestream::Custom.find_each无法找到的记录或类似的记录,因为它会在periscope列中搜索type的记录,不是Restream::Periscope

2)仅从restream_custom表中选择每种customperiscope等类型的记录,并为潜望镜创建Restream::Periscope,而不是Restream::Custom和试图在这里提供正确的类型。但是我发现它有点不合适,不干燥和不必要,并且想知道我是否可以用它做更漂亮的事情。

1 个答案:

答案 0 :(得分:0)

如果它不是一个重构太大,我会选择你的第一个选项1)将type设置为Restream::Periscope而不是periscope,主要是因为它是{{ 3}}

如果实施了选项1),你说你对此的另一个担忧是Restream::Periscope.find_each将不再返回其他&#34;类型&#34;的记录。并将根据子类自动进行相应筛选...确实有意义,因为.find_each正在查询Restream::Periscope,因此我很期望所有返回的记录都是type "Restream::Periscope"

现在,如果您想查询&#34;所有类型&#34;,那么您可以只查询&#34;父母&#34;类Restream::Service,您现在可以在其中执行以下操作:

Restream::Service.find_each(type: old_restream_custom.type)
# or
Restream::Service.create(type: old_restream_custom.type)

这是我的建议,除非当然重构所有代码真是一项重大任务。希望这有所帮助。

P.S。我无能为力但却注意到;你很漂亮:)