2017-08-30 19 views
0

大量のコードをリファクタリングし、dbスキーマを大きく変更しました。そして今、古いテーブルのレコードを新しいテーブルに移行するためのレーキタスクを作成しようとしています。rakeタスクとカスタムSTI名で無効な単一テーブル継承タイプ

私はこのようなクラスを持っています:

#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'のレコードを持っているので、それが有効な値であることが分かります。 これはどのような理由があり、この問題を解決するにはどうすればよいですか?

======

私は2つの方法で見ることができます:

1)だけperiscopeRestream::Periscopetypeを設定されていません。しかし、それはRestream::Periscope.find_eachまたはRestream::Custom.find_eachまたはそのようなsmthで見つけることができないレコードを作成します。Restream::Periscopeではなく、typeの列にperiscopeのレコードを検索するためです。

2)restream_customテーブルからなどcustomperiscope、それぞれのタイプのレコードだけを選択し、潜望鏡のためRestream::Periscope、ないRestream::Customを作成し、ここに正しい型を提供しようとしています。しかし、私はそれが未知の、乾燥していない、そして不必要なものであることを発見し、私がそれでより美しいものをすることができるかどうか疑問に思います。

答えて

0

それはリファクタリングの大きすぎるではない場合、私はそれがRails conventionあるので、主にちょうどtypeperiscopeRestream::Periscopeにしていないを設定するには、あなたの最初のオプション1)となるだろう。

オプション1)が実装されている場合、他の "タイプ"のレコードは返されず、サブクラスに応じて自動的にフィルタリングされます。 .find_eachRestream::Periscopeを照会しています。したがって、返されたすべてのレコードがtype"Restream::Periscope"のものであると私は期待しています。

今、あなたは「すべてのタイプ」を照会したい場合、あなたはちょうどあなたが今、次の操作を行うことができている、Restream::Serviceある「親」クラスに問い合わせることができる:

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

これは私の提案です。もちろん、あなたのコードをすべてリファクタリングするのは本当に大きな仕事です。これが何とか役立つことを願っています。

P.S.私は助けることができないが気づく。あなたは美しいです:)

+0

私はこれで終わると思います。しかし、私が本当に知りたかったことは、あなたが知っている... "賢い"ことです。 ActiveRecordがこれらが有効で、エラーを発生させないようにするために、クラスからロードする方法についての何か。私はそれを使うべき場所ではないかもしれませんが、私は本当にそれに興味があります。 – Ngoral

+0

Railsは、 'Restream :: Periscope'が' Another'Namespace :: Periscopeとは別の名前空間を適切に扱うので、 'type'の値として文字列定数すなわち' Restream :: Periscope'を使用していると思います'。これはおそらく、Railsが関係する限り、これが実際に実際にどのようなサブクラスであるかをまだ知ることのできない「潜望鏡」を識別するための「魔法の」ソリューションを持っていない理由です。しかし、私は限られた知識しか持っていません。おそらく私は何かを欠けているだけかもしれません。 –

+0

はい、私は何とかそれがそうしている理由を何とか理解しています。しかし、 'self.sti_name'を使うと、rails appを走らせている間に何かの理由で無視します。 – Ngoral

関連する問題