Critique my Stack Overflow schema I'm learning DB design.  How would you change the following schema which tries to replicate Stack Overflow's functionality:

create_table "questions", :force =&gt; true do |t|
    t.text      "question",         :null =&gt; false
    t.text      "description",  :null =&gt; false
    t.integer       "up_votes",         :null =&gt; false, :default =&gt; 0
    t.integer       "down_votes",       :null =&gt; false, :default =&gt; 0
  t.timestamps
end

create_table "answers", :force =&gt; true do |t|
    t.integer       "question_id",  :null =&gt; false
    t.text      "answer",               :null =&gt; false
    t.integer       "up_votes",         :null =&gt; false, :default =&gt; 0
    t.integer       "down_votes",       :null =&gt; false, :default =&gt; 0
  t.timestamps
end

create_table "question_comments", :force =&gt; true do |t|
    t.integer   "question_id",  :null =&gt; false
    t.text      "comment",          :null =&gt; false
  t.timestamps
end

create_table "answer_comments", :force =&gt; true do |t|
    t.integer   "answer_id",    :null =&gt; false
    t.text      "comment",      :null =&gt; false
  t.timestamps
end

create_table "tags", :force =&gt; true do |t|
    t.string        "tag",  :null =&gt; false, :limit =&gt; 100
  t.timestamps
end
add_index "tags", ["tag"], :name =&gt; "tag_UNIQUE", :unique =&gt; true

create_table "question_tags", :force =&gt; true do |t|
  t.integer     "question_id",  :null =&gt; false
  t.integer     "tag_id",               :null =&gt; false
  t.timestamps
end

create_table "users", :force =&gt; true do |t|
    t.string        "first_name",   :limit =&gt; 45,       :null =&gt; false
    t.string        "last_name",    :limit =&gt; 45,       :null =&gt; false
    t.string        "email",            :limit =&gt; 100,  :null =&gt; false
    t.string        "password",                                     :null =&gt; false
    t.string        "salt",                                             :null =&gt; false
  t.timestamps
end

create_table "user_votes", :force =&gt; true do |t|
    t.integer       "user_id",  :null =&gt; false
    t.integer       "question_id"
    t.integer       "answer_id"
    t.boolean       "is_positive_vote"
    t.timestamps
end

create_table "user_favorites", :force =&gt; true do |t|
    t.integer       "user_id",  :null =&gt; false
    t.integer       "question_id"
    t.integer       "answer_id"
    t.timestamps
end

create_table "question_flags", :force =&gt; true do |t|
    t.integer       "user_id",  :null =&gt; false
    t.integer       "question_id"
    t.timestamps
end

create_table "answer_flags", :force =&gt; true do |t|
    t.integer       "user_id",  :null =&gt; false
    t.integer       "question_id"
    t.timestamps
end

create_table "related_questions", :force =&gt; true do |t|
    t.integer       "question_id",                  :null =&gt; false
    t.integer       "related_question_id",  :null =&gt; false
    t.timestamps
end
Your answers table doesn't actually have an answerID, which is later referenced in your answer comments.

Your link tables for comments, I would have a primary key assigned that is separate from the answerid, since you don't want a composite key between answerID and comment (Think about updating/removing post logic). Apply the same to question comments.

Consider storing users against questions/answer submissions, otherwise, how will you know who posted it? Think about edit functionality too, do you want to audit changes?