Я работаю над приложением, которое будет управлять студентами, зачисленными на курс. В приложении будут пользователи, которые могут входить в систему и манипулировать студентами. Пользователи также могут комментировать студентов. Итак, три наших основных класса - это «Студент», «Пользователь» и «Комментарий». Проблема в том, что мне нужно связать отдельные комментарии с обеими другими моделями: User и Student. Итак, я начал с некоторого базового кода, подобного этому ...
class Student < ActiveRecord::Base
has_many :comments
end
class User < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :student
belongs_to :user
attr_accessible :comment
end
Таким образом, в таблице комментариев одна запись будет иметь следующие поля:
id
comment
student_id
user_id
created_at
updated_at
Это создает несколько проблем. Во-первых, хороший синтаксис Rails для создания связанных объектов не работает. Если я хочу сделать новый комментарий, я должен выбрать между внешними ключами. Итак ...
User.comments.create(attributes={})
OR
Student.comments.create(attributes={})
Другой вариант - произвольно выбрать один из внешних ключей и вручную добавить его в хэш attrs. Итак ...
User.comments.create(:comment => "Lorem ipsum", :student_id => 1)
Проблема с этой опцией заключается в том, что мне нужно перечислить student_id в attr_accessible в моей модели комментариев. Но я понимаю, что это создает угрозу безопасности, поскольку кто-то может технически прийти и связать комментарий с другим учеником, используя массовое задание.
Это приводит к дальнейшему вопросу о моделировании данных в целом с использованием Rails. Приложение, которое я сейчас создаю в Rails, - это то, которое я написал несколько лет назад на PHP / MySQL. Когда я впервые изучал SQL, большое значение придавалось идее нормализации. Так, например, если у вас есть таблица контактов, в которой хранятся имена и адреса, вы должны использовать множество связей с внешним ключом, чтобы избежать повторения данных. Если у вас есть столбец состояний, вы бы не хотели перечислять состояния напрямую. В противном случае вы могли бы потенциально иметь тысячи строк, которые содержат строковые значения, такие как «Техас». Гораздо лучше иметь отдельную таблицу состояний и связать ее с таблицей контактов, используя отношения внешнего ключа. Мое понимание хорошей теории SQL заключалось в том, что любые значения, которые могут повторяться, должны быть разделены на их собственные таблицы. Конечно, чтобы полностью нормализовать базу данных, вам, скорее всего, понадобится немало внешних ключей в таблице контактов. (state_id, пол_ид и т. д.)
Так, как можно поступить об этом «по пути рельсов»?
Для пояснения (извините, я знаю, что это становится длинным), я рассмотрел два других распространенных подхода: "has_many: through =>" и полиморфные ассоциации. Насколько я могу судить, ни одна из них не решает вышеуказанную проблему. И вот почему:
"has_many: through =>" отлично работает в случае с блогом. Итак, у нас есть комментарии, статьи и пользовательские модели. У пользователей есть много комментариев через статьи. (Такой пример появляется в Beginning Rails 3 от Apress. Кстати, отличная книга.) Проблема в том, что для того, чтобы это работало (если я не ошибаюсь), каждая статья должна принадлежать конкретному пользователю. В моем случае (где моя модель ученика здесь аналогична статье) ни один пользователь не владеет учеником. Поэтому я не могу сказать, что у пользователя есть много комментариев через студентов. Может быть несколько пользователей, комментирующих одного и того же ученика.
Наконец, у нас есть полиморфные ассоциации. Это прекрасно работает для нескольких внешних ключей, при условии, что ни одна запись не должна принадлежать более чем одному внешнему классу. В эпизоде RailsCasts # 154 Райан Бейтс приводит пример, где комментарии могут принадлежать статьям ИЛИ фотографиям ИЛИ событиям. Но что, если один комментарий должен принадлежать более чем одному?
Итак, в общем, я могу заставить мой сценарий Пользователь, Студент, Комментарий работать вручную, назначив один или оба внешних ключа, но это не решает проблему attr_accessible.
Заранее спасибо за любой совет!