Почему rails не уважает тип связанного объекта own_to с STI, когда его суперкласс является абстрактным? - PullRequest
4 голосов
/ 03 апреля 2011

Я столкнулся с этим довольно странным поведением в приложении rails, над которым я работаю.

У меня есть несколько типов Post в иерархии наследования и Post has_many 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 abstract (что на самом деле должно быть - суперкласс никогда не должен создаваться в этой модели):

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

_ (примечание: я отредактировал этот фрагмент кода, чтобы учесть предложение Tomafro ниже, поскольку установка self.abstract_class кажется более идиоматичной, чем переопределение self.abstract_class ?. Однако такое же поведение все еще сохраняется.)

... затем вызов ассоциации FeedEntry # post для ранее сохраненного объекта возвращает объектТип сообщения.Это выглядит довольно задом наперед (учитывая, что объявление абстрактного класса конкретно указывает на то, что этот класс не должен создаваться), и я не могу придумать причину такого поведения.

Итак, есть ли причина для этого?я не получаю, или это ошибка, или что-то еще?

Ответы [ 2 ]

6 голосов
/ 04 апреля 2011

Указав self.abstract_class = true в базовом объекте, вы фактически отключаете STI. Установка self.abstract_class = true фактически говорит ActiveRecord, что с этим классом связана , а не таблица базы данных, поэтому у ваших унаследованных классов будет своя собственная таблица базы данных.

Звучит так, как будто вы хотите удалить 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, а также имеете псевдо-абстрактный базовый класс. Надеюсь, это поможет!

0 голосов
/ 03 апреля 2011

Переопределив метод abstract_class? в суперклассе, abstract_class? вернет true для всех подклассов, а не только для суперкласса.

Вместо этого я думаю, что вы должны использовать:

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

Я не пробовал, но я верю, что это решит вашу проблему.

...