У вас есть несколько вариантов того, как смоделировать это в рельсах, однако первое, что я хотел бы предложить, это чтобы сэкономить время и проблемы позже, вы должны подойти к своему вопросу под другим углом.
Чтобы получить максимум от Rails, не следует начинать с проектирования базы данных. Вы должны начать с Модели данных, а затем искать способ сопоставления этой Модели данных со структурой базы данных, а не наоборот. Это тонкое различие, но оно подразумевает другое мышление, когда вы рассматриваете базу данных как второстепенное значение для вашей модели, а не наоборот. Это поможет понять проблему в долгосрочной перспективе.
В этом сценарии можно использовать две конструкции ActiveRecord: наследование в одной таблице и полиморфное наследование.
Наследование в одной таблице
Single Table Inheritance (STI) хранит модели с большим количеством общих функций в одной базовой таблице базы данных. В вашем примере вопросы и ответы, и в меньшей степени комментарии - это все похожие объекты. У них есть некоторый контент, автор, некоторые поля даты и времени для созданного и обновленного в и т. Д. Единственное различие между вопросом и ответом состоит в том, что вопросы «принадлежат» ответу. Комментарии немного сложнее, поскольку вы можете комментировать как Вопросы, так и ответы, а также, возможно, комментарии, хотя ваша Схема базы данных не отражает того, что это возможно.
С STI ваши модели Вопросов и Ответов хранятся не в отдельной таблице, а в одной таблице и помечаются именами классов. Реальные классы Вопросов и Ответов затем наследуются от Базового класса, в вашем случае «Post». Существует множество ресурсов, посвященных обсуждению ИППП, но этот может помочь
Полиморфное наследование
Это второй метод моделирования подобного поведения в рельсах. Это использует одну таблицу, в вашем случае сообщения для хранения данных, которые являются общими для двух классов. Эта таблица содержит столбцы, которые ссылаются на имя класса и экземпляр идентификатора базового объекта. Данные, специфичные для объекта, будут затем храниться в отдельной таблице для каждой модели.
Реализация (с использованием STI)
Чтобы смоделировать ваши данные с помощью STI, вы должны создать базовую модель постов, подобных этой
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.string :type
t.string :author
t.text :content
t.integer :parent_id
t.timestamps
end
end
def self.down
drop_table :posts
end
end
Тогда ваши модели будут выглядеть так
class Post < ActiveRecord::Base
end
class Question < Post
has_many :answers, :foreign_key => :parent_id
has_many :comments, :foreign_key => :parent_id
end
class Answer < Post
belongs_to :question, :foreign_key => :parent_id
has_many :comments, :foreign_key => :parent_id
end
class Comment < Post
belongs_to :question, :foreign_key => :parent_id
belongs_to :answer, :foreign_key => :parent_id
end
И пример кода
q1 = Question.new(:author => 'Steve', :content => 'What is 2 + 2')
q1c1 = q1.comments.build(:author => 'Malcolm',
:content => "Good question, i'd been wondering that myself")
q1a1 = q1.answers.build(:author => 'John', :content => '2+2 = 5')
q1a2 = q1.answers.build(:author => 'Phil', :content => '2+2 is a sum')
q1a1c1 = q1a1.comments.build(:author => 'Chris',
:content => 'Sorry John it should be 4')
q1a2c1 = q1a2.comments.build(:author => 'Steve',
:content => 'Hi Phil thanks for stating the obvious!')
q1.save
qu = Question.find(:first)
puts "#{qu.author} asked #{qu.content}"
qu.comments.each {|qc| puts "\t#{qc.author} commented #{qc.content}"}
qu.answers.each do |ans|
puts "\t#{ans.author} answered with #{ans.content}"
ans.comments.each do |comm|
puts "\t\t#{comm.author} commented #{comm.content}"
end
end
Этот код дает следующие результаты
Steve asked What is 2 + 2
Malcolm commented Good question, i'd been wondering that myself
John answered with 2+2 = 5
Chris commented Sorry John it should be 4
Phil answered with 2+2 is a sum
Steve commented Hi Phil thanks for stating the obvious!
В базе данных есть одна таблица сообщений со следующей структурой
CREATE TABLE "posts" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"type" varchar(255),
"author" varchar(255),
"content" text,
"parent_id" integer,
"created_at" datetime,
"updated_at" datetime
);
А содержание данных после примера выглядит следующим образом: -
1|Question|Steve|What is 2 + 2||2009-06-13 09:52:20|2009-06-13 09:52:20
2|Answer|John|2+2 = 5|1|2009-06-13 09:52:20|2009-06-13 09:52:20
3|Comment|Chris|Sorry John it should be 4|2|2009-06-13 09:52:20|2009-06-13 09:52:20
4|Answer|Phil|2+2 is a sum|1|2009-06-13 09:52:20|2009-06-13 09:52:20
5|Comment|Steve|Hi Phil thanks for stating the obvious!|4|2009-06-13 09:52:20|2009-06-13 09:52:20
6|Comment|Malcolm|Good question, i'd been wondering that myself|1|2009-06-13 09:52:20|2009-06-13 09:52:20
Возможно, вам будет проще разделить модель комментариев на QuestionComments и AnswerComments. Это сделало бы прямой sql намного проще.