web-dev-qa-db-ja.com

単一テーブルの継承とRails

奇妙なデザインの問題に悩まされています。

私は2種類のプロファイルモデルに取り組んでいます。

  • ユーザープロファイル(ユーザーに属する)
  • サイト内で「ボット」として維持されているもの(誰にも属していない)

これらの2つのタイプのプロファイルの典型的なOO動作は同じですが、重要な属性/プロパティのみが共通(非常に重要なものは5〜6個)、他の "interests etc"などのプロパティ(ほぼ10〜15のプロパティ)はボットプロファイルにはありません

この以前に取り組んだコーダーは、ボットプロファイル用の個別のモデル/コントローラーを作成しました/ユーザープロファイルはどこにでも多くの冗長性を作成し、予想通りに維持するのが困難で、テストなどを記述しました。DRYこれで、少なくともこれらの冗長性の問題の一部またはすべてを解決できます。

誰かが解決策として単一テーブル継承を提案しました

誰かが代わりに多態的な関連を使うことを提案しました。

より良いアプローチは何ですか。実際にSTIを使用するのはいつですか?

私の考えでは、STIはモデルの属性が同じで、動作が異なる場合に最もよく使用されます。

私は何ができるかについての考え?

53
Rishav Rastogi

属性が同じで動作が異なる場合にSTIを最も有用であると特徴付けることは「ほぼ適切」ですが、おそらく少し制限があります。名前が示すように、異なるタイプのオブジェクト間のデータベーススタイルの関係ではなく、明確なOOスタイルの継承関係がある場合に、STIを使用するのが好きです。

ボットとユーザーの間に共通のコードがある場合、私はSTIが勝者のように聞こえると思います。いくつかの一般的な属性がある場合、それはおそらくあまり適用されませんが、まだ試す価値があります。

私はかなり実験的な人なので、私はそれを試してみることをお勧めします。コードを分岐し、モデルをSTI関係にリファクタリングします。それが本当に物事を乾かすか、または他の問題のために頭痛のセットを交換するだけかを確認してください。

あまりメリットがないと思うのは、コントローラーを枯渇させることです。私の経験では、STIモデルは同様に関連するコントローラーに変換されないことがよくあります。しかし、それは実験する別のものになるでしょう。時には勝利がある場合もあれば、ない場合もあります。

35
womble

STIを使用するためのヒントを含む、このまさにこのトピックに関する記事を書きました。

Railsでの単一テーブルの継承

つまり、一部の共有データだけでなく、オブジェクト間に明確なOOスタイルの継承関係(wombleによって雄弁に述べられているように)が必要です。自然で明白なクラス階層がない場合、アプリケーションが進化するにつれてSTI設計を維持することが困難になる可能性があります。

次に、1つのテーブルにすべてのデータを含めることが重要かどうかを検討する必要があります。多態的な関連付けを使用すると、データベースクエリがより複雑になり、おそらく遅くなります。すべてのオブジェクトをサイトにまとめてリストすることを計画している場合(例:表)、STIが適しています。

3番目に、子クラスに固有の属性が多すぎないことを確認します。すべてのデータが1つのテーブルに含まれているため、非グローバル列を多数必要としません。これらはスペースを占有するだけでなく(大きな問題ではありません)、データ構造を混乱させます。 「特別な」列がある場合は、コードで明示的に説明する必要があります。

最後に、STIを使用する場合は、すべての子モデルに単一のコントローラーを使用することを強くお勧めします。コントローラーの主な機能は、オブジェクトへのアクセスを提供することであり、オブジェクトに非常に異なる方法でアクセスする必要がある場合、STIは最初から正しい設計の選択ではなかった可能性があります。

さらに役立つヒントについては、私の記事(上記のリンク)を確認してください。

29
Alex Reisner

おそらくSTIを使用するか、特別な機能をまったく使用しないでしょう。すべてをプロファイルと呼ぶことができ、ユーザーがnilの場合、それが「ボット」であるかどうかを確認できます。 STIを使用せずに「タイプ」フィールドを格納することもできます。

STIを使用するという私の決定に影響を与えるものがあります。

  • ボット固有のロジックがあるかどうか
  • ボットの数とユーザープロファイルの数(ボットの数が少ないということは、STIが問題ないことを意味します-ボットがたくさんあり、別の場所に保存する可能性があります)

STIを回避する理由は、それが邪魔になる場合があるためです。たとえば、オブジェクトをあるタイプから別のタイプ(この場合はボットからプロファイル)に変更するのはかなり面倒です。単純な「タイプ」フィールドの方が良い場合があります。

STIを使用する場合は、おそらく共通の基本クラスが必要になることに注意してください。したがって、ProfileBotProfile、およびUserProfileが必要になる場合があります。名前はあなた次第です。 :)

5
wuputah

Rails STI-ほとんどのプラグイン(など))は、完全にはサポートしていません。一般的なプラグインの多くにパッチを適用していることに気づくでしょう。

4
Sarah Mei