Sie haben mehrere Möglichkeiten, wie diese in Schienen zu modellieren, aber das erste, was ich vorschlagen würde, ist, dass zu speichern, um Zeit und Ärger später sollten Sie Ihre Frage aus einem anderen Blickwinkel betrachten.
Um das Beste aus Rails herauszuholen, sollten Sie nicht mit einem Datenbankentwurf beginnen. Sie sollten mit einem Datenmodell beginnen und dann die Art und Weise betrachten, wie dieses Datenmodell einer Datenbankstruktur zugeordnet wird und nicht umgekehrt. Dies ist ein subtiler Unterschied, beinhaltet jedoch eine andere Denkweise, bei der Sie Ihre Datenbank als sekundäre Betrachtung Ihres Modells sehen und nicht umgekehrt. Dies wird das Problem auf lange Sicht einfacher verständlich machen.
Es gibt zwei ActiveRecord-Konstrukte, die in diesem Szenario verwendet werden können. Sie sind Single Table-Vererbung und polymorphe Vererbung.
Single Table Inheritance
Single Table Inheritance (STI) speichert Modelle mit viel gemeinsam genutzte Funktionalität innerhalb der gleichen zugrunde liegenden Datenbanktabelle. In Ihrem Beispiel sind Fragen und Antworten und in geringerem Maße Kommentare ähnliche Objekte. Sie haben einen Inhalt, einen Autor, einige Datetime-Felder für created_at und werden aktualisiert usw. Der einzige Unterschied zwischen einer Frage und einer Antwort besteht darin, dass Fragen zu einer Antwort "gehören". Kommentare sind etwas kniffliger, da Sie sowohl Fragen als auch Antworten und vielleicht auch Kommentare kommentieren können, obwohl Ihr Datenbankschema nicht zeigt, dass dies möglich ist.
Mit STI werden Ihre Frage- und Antwortmodelle nicht in einer separaten Tabelle, sondern in einer einzigen Tabelle gespeichert und mit den Klassennamen gekennzeichnet. Die eigentlichen Frage- und Antwortklassen erben dann von der Basisklasse, in Ihrem Fall "Post". Es gibt zahlreiche Ressourcen ou es STI diskutieren aber this one helfen kann
Polymorphe Inheritance
Dies ist das zweite Verfahren zum Modellieren ein ähnliches Verhalten in Schienen. Dies verwendet eine einzelne Tabelle, in Ihrem Fall Beiträge, um die Daten zu speichern, die den beiden Klassen gemeinsam sind. Diese Tabelle enthält Spalten, die auf den Klassennamen und die ID-Instanz des Basisobjekts verweisen. Die für das Objekt spezifischen Daten werden dann in einer separaten Tabelle pro Modell gespeichert.
Implementation (mit STI)
Um Ihre Daten unter Verwendung von STI zu modellieren dann würden Sie dies würde
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
Ihre Modelle ein Basismodell der Beiträge wie schaffen dann folgendermaßen aussehen
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
Und einige Beispielcode
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
Dieser Code erzeugt die folgenden Ergebnisse
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!
in der Datenbank suchen, gibt eine einzelne Beiträge Tabelle mit der folgenden Struktur ist
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
);
und der Dateninhalt nach dem Beispiel wie folgt: -
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
Sie können es leichter finden, die Kommentare zu teilen Modell in FrageKommentare und AntwortKommentare. Dies würde gerade SQL viel einfacher machen.
Das ist großartig. Danke, dass Sie sich die Zeit genommen haben, eine so umfassende Antwort zu schreiben. Obwohl ich Ihren Vorschlag, STI über einen polymorphen Ansatz zu verwenden, mag, besteht ein Nachteil von STI gegenüber Class Table Inheritance everything2.com/title/... darin, dass Sie einige ungenutzte Spalten in Klassen erhalten, die von Post abgeleitet sind. Einer Frage können beispielsweise Tags zugeordnet sein, und das könnte eine Spalte in der Tabelle "Fragen" sein, unter STI sollte es jedoch eine Spalte in der Tabelle "Beiträge" sein, und Antworten und Kommentare enden mit einer Spalte "Tags". –
... aber da Rails nur STI und polymorphe Assoziationen anbietet, scheint STI die bessere Wahl zu sein, selbst wenn Sie bei diesem Ansatz mit extra unbenutzten Spalten enden. Insgesamt sind Sie jedoch richtig - ich muss das Problem aus Sicht der Rails und nicht aus einer Datenbankperspektive betrachten. Das wird etwas gewöhnungsbedürftig sein, fürchte ich. –
Hallo Charlie, ich werde das kommentieren, aber ich habe gerade viele Stunden draußen getrunken, jetzt ist es nicht an der Zeit. Ich werde morgen Kommentare und/oder eine polymorphe Lösung schreiben. –