4

私が取り組んでいる Rails アプリケーションで、このやや奇妙な動作に遭遇しました。

継承階層に複数のタイプの投稿があり、投稿には多数の FeedEntries があります。

class Post < ActiveRecord::Base
    has_many :feed_entries
end

class Post::BlogPost < Post; end
class Post::Discussion < Post; end
class Post::Article < Post; end

class FeedEntry < ActiveRecord::Base
    belongs_to :post
end

以前のようにすべてをセットアップしたら、保存されたオブジェクトで FeedEntry#post を呼び出すと、予想どおり、常に正しい (サブクラス) タイプのオブジェクトが返されます。ただし、Post を抽象化すると (実際にはそうあるべきです - スーパークラスはこのモデルでインスタンス化されるべきではありません):

class Post < ActiveRecord::Base
    has_many :feed_entries
    self.abstract_class = true
end

_(注: 以下の tomafro の提案を考慮して、このコード スニペットを編集しました。self.abstract_class を設定することは、self.abstract_class をオーバーライドするよりも慣用的なように思われるためです。しかし、同じ動作は依然として持続します。)

...次に、以前に保存されたオブジェクトで FeedEntry#post 関連付けを呼び出すと、タイプ Post のオブジェクトが返されます。これはかなり逆向きに思えます (抽象クラスの宣言が、そのクラスをインスタンス化してはならないことを明確に示していることを考えると)、この動作の理由は考えられません。

それで、私が得ていないこれには何らかの理由がありますか、それともバグですか、それとも何か他のものですか?

4

2 に答える 2

7

基本オブジェクトで指定することによりself.abstract_class = true、本質的に STI を無効にします。設定 は実際には、そのクラスに関連付けられたデータベース テーブルがないself.abstract_class = trueことを ActiveRecord に通知するため、継承されたクラスはそれぞれ独自のデータベース テーブルを持つことになります。

クラスがtypeでないself.abstract_class = true場合にのみインスタンス化を許可するために initialize メソッドを使用して、抽象クラスを削除してシミュレートすることのように思えます。Post

例えば:

class Post < ActiveRecord::Base    
  def initialize 
    raise "Post cannot be instantiated directly" if self.class == Post   
  end
end

このようにして、STI モデルを維持し、疑似抽象基本クラスも作成します。お役に立てれば!

于 2011-04-04T12:45:41.457 に答える
0

abstract_class?スーパークラスのメソッドをオーバーライドすることにより、スーパーabstract_class?クラスだけでなく、すべてのサブクラスに対して true を返します。

代わりに、次を使用する必要があると思います:

class Post < ActiveRecord::Base
  self.abstract_class = true
end

試したことはありませんが、これで問題が解決すると思います。

于 2011-04-03T13:51:21.433 に答える