From 0fe7d2b7c9400b4a4731d8a0dd9a882eae929b52 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Wed, 18 Jul 2012 12:53:32 -0400 Subject: [PATCH] get rid of the commentable collection in the database --- app.rb | 22 +++++++++--------- models/comment_thread.rb | 17 +++++++++----- models/commentable.rb | 28 +++++++++++------------ models/subscription.rb | 13 +++++++++-- models/user.rb | 10 +++++++-- spec/app_spec.rb | 48 ++++++++++++++++++---------------------- 6 files changed, 75 insertions(+), 63 deletions(-) diff --git a/app.rb b/app.rb index 47fe38d..3ff9ddb 100644 --- a/app.rb +++ b/app.rb @@ -19,19 +19,17 @@ Mongoid.logger.level = Logger::INFO Dir[File.dirname(__FILE__) + '/models/*.rb'].each {|file| require file} -delete '/api/v1/:commentable_type/:commentable_id/threads' do |commentable_type, commentable_id| - commentable = Commentable.find_or_initialize_by(commentable_type: commentable_type, commentable_id: commentable_id) - commentable.destroy - commentable.to_hash.to_json +delete '/api/v1/:commentable_id/threads' do |commentable_id| + Commentable.find(commentable_id).comment_threads.destroy_all + {}.to_json end -get '/api/v1/:commentable_type/:commentable_id/threads' do |commentable_type, commentable_id| - commentable = Commentable.find_or_create_by(commentable_type: commentable_type, commentable_id: commentable_id) - commentable.comment_threads.map{|t| t.to_hash(recursive: params["recursive"])}.to_json +get '/api/v1/:commentable_id/threads' do |commentable_id| + Commentable.find(commentable_id).comment_threads.map{|t| t.to_hash(recursive: params["recursive"])}.to_json end -post '/api/v1/:commentable_type/:commentable_id/threads' do |commentable_type, commentable_id| - commentable = Commentable.find_or_create_by(commentable_type: commentable_type, commentable_id: commentable_id) +post '/api/v1/:commentable_id/threads' do |commentable_id| + commentable = Commentable.find(commentable_id)#_or_create_by(commentable_type: commentable_type, commentable_id: commentable_id) thread = commentable.comment_threads.new(params.slice(*%w[title body course_id])) thread.author = User.find_or_create_by(external_id: params["user_id"]) if params["user_id"] thread.save! @@ -120,8 +118,8 @@ post '/api/v1/users/:user_id/subscriptions' do |user_id| User.find_or_create_by(external_id: params["source_id"]) when "thread" CommentThread.find(params["source_id"]) - else - Commentable.find_or_create_by(commentable_type: params["source_type"], commentable_id: params["source_id"]) + when "other" + Commentable.find(params["source_id"])#find_or_create_by(commentable_type: params["source_type"], commentable_id: params["source_id"]) end user.subscribe(source).to_hash.to_json end @@ -134,7 +132,7 @@ delete '/api/v1/users/:user_id/subscriptions' do |user_id| when "thread" CommentThread.find(params["source_id"]) else - Commentable.find_or_create_by(commentable_type: params["source_type"], commentable_id: params["source_id"]) + Commentable.find(params["source_id"])#find_or_create_by(commentable_type: params["source_type"], commentable_id: params["source_id"]) end user.unsubscribe(source).to_hash.to_json end diff --git a/models/comment_thread.rb b/models/comment_thread.rb index 1bb9ac5..96669cd 100644 --- a/models/comment_thread.rb +++ b/models/comment_thread.rb @@ -9,13 +9,12 @@ class CommentThread < Content field :title, type: String field :body, type: String field :course_id, type: String, index: true + field :commentable_id, type: String, index: true belongs_to :author, class_name: "User", inverse_of: :comment_threads, index: true, autosave: true - belongs_to :commentable, index: true, autosave: true has_many :comments, dependent: :destroy, autosave: true# Use destroy to envoke callback on the top-level comments TODO async - has_many :subscriptions, as: :source - attr_accessible :title, :body, :course_id + attr_accessible :title, :body, :course_id, :commentable_id validates_presence_of :title validates_presence_of :body @@ -24,6 +23,14 @@ class CommentThread < Content after_create :handle_after_create + def commentable + Commentable.find(commentable_id) + end + + def subscriptions + Subscription.where(source_id: id.to_s, source_type: self.class.to_s) + end + def subscribers subscriptions.map(&:subscriber) end @@ -44,8 +51,8 @@ private notification = Notification.new( notification_type: "post_topic", info: { - commentable_id: commentable.commentable_id, - commentable_type: commentable.commentable_type, + commentable_id: commentable_id, + #commentable_type: commentable.commentable_type, thread_id: id, thread_title: title, }, diff --git a/models/commentable.rb b/models/commentable.rb index 944c00d..9255c6b 100644 --- a/models/commentable.rb +++ b/models/commentable.rb @@ -1,26 +1,24 @@ class Commentable - include Mongoid::Document - field :commentable_type, type: String - field :commentable_id, type: String + attr_accessor :id + alias_attribute :_id, :id + + class << self; alias_method :find, :new; end - has_many :comment_threads, dependent: :destroy - has_many :subscriptions, as: :source + def initialize(id) + self.id = id + end - attr_accessible :commentable_type, :commentable_id + def comment_threads + CommentThread.where(commentable_id: id) + end - validates_presence_of :commentable_type - validates_presence_of :commentable_id - validates_uniqueness_of :commentable_id, scope: :commentable_type - - index [[:commentable_type, Mongo::ASCENDING], [:commentable_id, Mongo::ASCENDING]] + def subscriptions + Subscription.where(source_id: id.to_s, source_type: self.class.to_s) + end def subscribers subscriptions.map(&:subscriber) end - def to_hash(params={}) - as_document.slice(*%w[_id commentable_type commentable_id]) - end - end diff --git a/models/subscription.rb b/models/subscription.rb index 76273c5..67ac89a 100644 --- a/models/subscription.rb +++ b/models/subscription.rb @@ -2,8 +2,9 @@ class Subscription include Mongoid::Document include Mongoid::Timestamps - belongs_to :subscriber, class_name: "User", autosave: true, index: true - belongs_to :source, polymorphic: true, autosave: true, index: true + field :subscriber_id, type: String + field :source_id, type: String + field :source_type, type: String index [[:subscriber_id, Mongo::ASCENDING], [:source_id, Mongo::ASCENDING], [:source_type, Mongo::ASCENDING]] @@ -11,4 +12,12 @@ class Subscription as_document end + def subscriber + User.find(subscriber_id) + end + + def source + source_type.constantize.find(source_id) + end + end diff --git a/models/user.rb b/models/user.rb index 72e1af4..a7de637 100644 --- a/models/user.rb +++ b/models/user.rb @@ -7,13 +7,19 @@ class User has_many :comments has_many :comment_threads, inverse_of: :author has_many :activities, class_name: "Notification", inverse_of: :actor - has_many :subscriptions_as_source, class_name: "Subscription", as: :source - has_many :subscriptions_as_subscriber, class_name: "Subscription", inverse_of: :subscriber has_and_belongs_to_many :notifications, inverse_of: :receivers validates_presence_of :external_id validates_uniqueness_of :external_id + def subscriptions_as_source + Subscription.where(source_id: id.to_s, source_type: self.class.to_s) + end + + def subscriptions_as_subscriber + Subscription.where(subscriber_id: id.to_s) + end + def to_hash(params={}) as_document.slice(*%w[_id external_id]) end diff --git a/spec/app_spec.rb b/spec/app_spec.rb index a024bdd..9304f71 100644 --- a/spec/app_spec.rb +++ b/spec/app_spec.rb @@ -11,17 +11,15 @@ end def init_without_subscriptions Comment.delete_all CommentThread.delete_all - Commentable.delete_all User.delete_all Notification.delete_all Subscription.delete_all - commentable = Commentable.new(commentable_type: "questions", commentable_id: "1") - commentable.save! + commentable = Commentable.new("question_1") user = User.create!(external_id: "1") - thread = commentable.comment_threads.new(title: "I can't solve this problem", body: "can anyone help me?", course_id: "1") + thread = CommentThread.new(title: "I can't solve this problem", body: "can anyone help me?", course_id: "1", commentable_id: commentable.id) thread.author = user thread.save! @@ -42,7 +40,7 @@ def init_without_subscriptions comment1.author = user comment1.save! - thread = commentable.comment_threads.new(title: "This problem is wrong", body: "it is unsolvable", course_id: "2") + thread = CommentThread.new(title: "This problem is wrong", body: "it is unsolvable", course_id: "2", commentable_id: commentable.id) thread.author = user thread.save! @@ -76,7 +74,6 @@ end def init_with_subscriptions Comment.delete_all CommentThread.delete_all - Commentable.delete_all User.delete_all Notification.delete_all Subscription.delete_all @@ -86,14 +83,11 @@ def init_with_subscriptions user2.subscribe(user1) - commentable = Commentable.new(commentable_type: "questions", commentable_id: "1") + commentable = Commentable.new("question_1") user1.subscribe(commentable) user2.subscribe(commentable) - commentable.save! - commentable = commentable.reload - - thread = commentable.comment_threads.new(title: "I can't solve this problem", body: "can anyone help me?", course_id: "1") + thread = CommentThread.new(title: "I can't solve this problem", body: "can anyone help me?", course_id: "1", commentable_id: commentable.id) thread.author = user1 user2.subscribe(thread) thread.save! @@ -110,7 +104,7 @@ def init_with_subscriptions comment2.author = user2 comment2.save! - thread = commentable.comment_threads.new(title: "This problem is wrong", body: "it is unsolvable", course_id: "2") + thread = CommentThread.new(title: "This problem is wrong", body: "it is unsolvable", course_id: "2", commentable_id: commentable.id) thread.author = user2 thread.save! end @@ -118,16 +112,16 @@ end describe "app" do describe "commentables" do before(:each) { init_without_subscriptions } - describe "DELETE /api/v1/:commentable_type/:commentable_id/threads" do - it "delete the commentable object and all of its associated comment threads and comments" do - delete '/api/v1/questions/1/threads' + describe "DELETE /api/v1/:commentable_id/threads" do + it "delete all associated threads and comments of a commentable" do + delete '/api/v1/question_1/threads' last_response.should be_ok - Commentable.count.should == 0 + Commentable.find("question_1").comment_threads.count.should == 0 end end - describe "GET /api/v1/:commentable_type/:commentable_id/threads" do + describe "GET /api/v1/:commentable_id/threads" do it "get all comment threads associated with a commentable object" do - get "/api/v1/questions/1/threads" + get "/api/v1/question_1/threads" last_response.should be_ok threads = Yajl::Parser.parse last_response.body threads.length.should == 2 @@ -135,7 +129,7 @@ describe "app" do threads.index{|c| c["body"] == "it is unsolvable"}.should_not be_nil end it "get all comment threads and comments associated with a commentable object" do - get "/api/v1/questions/1/threads", recursive: true + get "/api/v1/question_1/threads", recursive: true last_response.should be_ok threads = Yajl::Parser.parse last_response.body threads.length.should == 2 @@ -154,9 +148,9 @@ describe "app" do not_for_me["children"].first["body"].should == "not for me neither!" end end - describe "POST /api/v1/:commentable_type/:commentable_id/threads" do + describe "POST /api/v1/:commentable_id/threads" do it "create a new comment thread for the commentable object" do - post '/api/v1/questions/1/threads', title: "Interesting question", body: "cool", course_id: "1", user_id: "1" + post '/api/v1/question_1/threads', title: "Interesting question", body: "cool", course_id: "1", user_id: "1" last_response.should be_ok CommentThread.count.should == 3 CommentThread.where(title: "Interesting question").first.should_not be_nil @@ -380,17 +374,17 @@ describe "app" do end it "subscribe a commentable" do user3 = User.find_or_create_by(external_id: "3") - post "/api/v1/users/#{user3.external_id}/subscriptions", source_type: "questions", source_id: "1" + post "/api/v1/users/#{user3.external_id}/subscriptions", source_type: "other", source_id: "question_1" last_response.should be_ok - Commentable.first.subscribers.length.should == 3 - Commentable.first.subscribers.should include user3 + Commentable.find("question_1").subscribers.length.should == 3 + Commentable.find("question_1").subscribers.should include user3 end it "unsubscribe a commentable" do user2 = User.find_or_create_by(external_id: "2") - delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "questions", source_id: "1" + delete "/api/v1/users/#{user2.external_id}/subscriptions", source_type: "other", source_id: "question_1" last_response.should be_ok - Commentable.first.subscribers.length.should == 1 - Commentable.first.subscribers.should_not include user2 + Commentable.find("question_1").subscribers.length.should == 1 + Commentable.find("question_1").subscribers.should_not include user2 end it "subscribe a comment thread" do user1 = User.find_or_create_by(external_id: "1")