ИППП и полиморфы
У меня проблема с моим кодом
class Post < ActiveRecord::Base
end
class NewsArticle < Post
has_many :comments, :as => :commentable, :dependent => :destroy, :order => 'created_at'
end
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true, :counter_cache => true
end
И в попытке пойдите, чтобы получить комментарии к некоторым NewsArticle, я вижу в журналах что-то вроде
Comment Load (0.9ms) SELECT "comments".* FROM "comments" WHERE ("comments"."commentable_id" = 1 and "comments"."commentable_type" = 'Post') ORDER BY created_at
Странно, что "commentable_type" = 'Post'.
Что не так?
PS: Rails 2.3.5 && ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10]
Ответы
Ответ 1
В поле commentable_type необходимо сохранить имя таблицы, содержащей данные, после того, как эта строка будет загружена из правой таблицы, унаследованный тип будет загружен из типа в таблице Сообщения.
Итак:
Здесь комментарий указывает на таблицу, на которую он комментирует. Таблица posts, id 1
>> Comment.first
=> #<Comment id: 1, commentable_id: 1, commentable_type: "Post", body: "test", created_at: "2010-04-09 00:56:36", updated_at: "2010-04-09 00:56:36">
Затем для загрузки NewsArticle id 1 загружается из сообщений, а тип там указывает на статью News.
>> Comment.first.commentable
=> #<NewsArticle id: 1, type: "NewsArticle", name: "one", body: "body", created_at: "2010-04-09 00:55:35", updated_at: "2010-04-09 00:55:35">
>> Comment.first.commentable.class.table_name
=> "posts"
Если commentable_type сохранено "NewsArticle"
, ему придется посмотреть на класс, чтобы определить таблицу. Таким образом, он может просто смотреть на стол и беспокоиться о типе, когда он туда попадает.
Ответ 2
Взгляните на раздел Полиморфные ассоциации ActiveRecord:: Ассоциации API. Существует немного информации об использовании полиморфных ассоциаций в сочетании с наложением одной таблицы. После второго примера кода в этом разделе я думаю, что это может быть близко к тому, что вы хотите
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true, :counter_cache => true
def commentable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
end
end
class Post < ActiveRecord::Base
has_many :comments, :as => :commentable, :dependent => :destroy, :order => 'created_at'
end
class NewsArticle < Post
end
Ответ 3
def commentable_type = (sType) супер (sType.to_s.classify.constantize.base_class.to_s) конец
Этот метод возвращает класс как Post, что делать, если вы хотите сохранить унаследованный класс Post в качестве commentable_type?
Ответ 4
Хороший вопрос. У меня была такая же проблема с Rails 3.1. Похоже, проблема еще не решена. По-видимому, использование полиморфных ассоциаций в сочетании с однонаправленным наследованием (STI) в Rails является немного сложным.
Текущая документация Rails для Rails 3.2 дает этот совет для объединения полиморфных ассоциаций и STI:
Использование полиморфных ассоциаций в сочетании с одной таблицей Наследование (STI) немного сложно. Для того чтобы ассоциации работайте, как ожидалось, убедитесь, что вы храните базовую модель для ИППП модели в столбце типа полиморфной ассоциации.
В вашем случае базовой моделью будет "Post", то есть "commentable_type" должен быть "Post" для всех комментариев.
Ответ 5
Технически, в этом нет ничего плохого. Когда Rails имеет дело с полиморфной ассоциацией, а связанный с ним объект использует STI, он просто использует базовый класс как тип (в вашем случае "commentable_type" ).
Если у вас есть Post и NewsArticle в отдельных таблицах, очевидно, commentable_type будет отображаться как Post и NewsArticle соответственно.