我正在考虑以下数据库结构,但我不确定哪种类型的Rails模型关系会支持我定义的数据库密钥。任何人都可以建议这在Rails中如何起作用吗?
Posts
id
post_type -- must be 'Q' or 'A'
author
date
content
UNIQUE KEY (post_id, post_type) -- to support foreign keys
Questions
id
post_id
post_type -- must be 'Q'
FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
Answers
id
post_id
post_type -- must be 'A'
question_id
FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
FOREIGN KEY (question_id) REFERENCES Questions(post_id)
Comments
id
post_id
author
date
content
FOREIGN KEY (post_id) REFERENCES Posts(post_id)
上面的草图将转换为以下实现:
CREATE TABLE Posts (
post_id SERIAL PRIMARY KEY,
post_type CHAR(1), -- must be 'Q' or 'A'
-- other columns common to both types of Post
UNIQUE KEY (post_id, post_type) -- to support foreign keys
) ENGINE=InnoDB;
CREATE TABLE Comments (
comment_id SERIAL PRIMARY KEY,
post_id BIGINT UNSIGNED NOT NULL,
-- other columns for comments (e.g. date, who, text)
FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB;
CREATE TABLE Questions (
post_id BIGINT UNSIGNED PRIMARY KEY,
post_type CHAR(1), -- must be 'Q'
-- other columns specific to Questions
FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
) ENGINE=InnoDB;
CREATE TABLE Answers (
post_id BIGINT UNSIGNED PRIMARY KEY,
post_type CHAR(1), -- must be 'A'
question_id BIGINT UNSIGNED NOT NULL,
-- other columns specific to Answers
FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
FOREIGN KEY (question_id) REFERENCES Questions(post_id)
) ENGINE=InnoDB;
答案 0 :(得分:11)
关于如何在rails中建模,你有几个选择,但我建议的第一件事是,为了节省你自己的时间和麻烦,你应该从不同的角度处理你的问题。
为了从Rails中获得最大收益,您不应该从数据库设计开始。您应该从数据模型开始,然后查看将此数据模型映射到数据库结构的方式,而不是相反。这是一个微妙的差异,但涉及不同的思维模式,您将数据库视为模型的次要考虑因素,而不是相反。从长远来看,这将使问题更容易理解。
在这种情况下可以使用两种ActiveRecord构造,它们是单表继承和多态继承。
单表继承
单表继承(STI)在同一基础数据库表中存储具有大量共享功能的模型。在您的示例问题和答案中,在较小程度上,评论都是类似的对象。他们有一些内容,作者,created_at的一些日期时间字段和更新等。问题和答案之间的唯一区别是问题“属于”答案。评论稍微复杂一些,因为您可以对问题和答案进行评论,也可以对评论进行评论,尽管您的数据库架构并未反映这是可能的。
使用STI,您的问答模型不会存储在单独的表中,而是存储在单个表中,并使用类名进行标记。然后,实际的问答类继承自Base类,在您的情况下为“Post”。有很多资源可以讨论STI,但this one可能有帮助
多态继承
这是在rails中建模类似行为的第二种方法。这使用单个表,在您的案例帖子中存储两个类之间通用的数据。此表包含引用基类对象的类名和id实例的列。然后,特定于对象的数据将存储在每个模型的单独表中。
实施(使用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更容易。
答案 1 :(得分:0)
这个解决方案是否也可以使用例如:
之间的has_and_belongs_to_many运动员和运动员?
s1 = Sportsmen.new(:name=> “Günter”)
t1 = Trainer.new(:name=> „Hans“)
t2 = Trainer.new(:name=> „Joachim“)
is this correct ?
S1t1 = s1.t1
S1t2 = s1.t2