Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/helpers/bubbles_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def bubble_rotation(bubble)

def bubble_size(bubble)
rank =
case bubble.activity_count
case bubble.activity_score
when 0..5 then "one"
when 6..10 then "two"
when 11..25 then "three"
Expand Down
4 changes: 2 additions & 2 deletions app/models/account.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
class Account < ApplicationRecord
include Joinable

has_many :users, dependent: :destroy

has_many :buckets, dependent: :destroy
has_many :bubbles, through: :buckets

has_many :users, dependent: :destroy

has_many :workflows, dependent: :destroy
has_many :stages, through: :workflows, class_name: "Workflow::Stage"

Expand Down
18 changes: 4 additions & 14 deletions app/models/bubble.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Bubble < ApplicationRecord
include Assignable, Boostable, Colored, Eventable, Messages, Poppable, Searchable, Staged, Taggable
include Assignable, Boostable, Colored, Commentable, Eventable, Messages, Poppable, Searchable, Staged, Taggable

belongs_to :bucket, touch: true
belongs_to :creator, class_name: "User", default: -> { Current.user }
Expand All @@ -10,19 +10,9 @@ class Bubble < ApplicationRecord

scope :reverse_chronologically, -> { order created_at: :desc, id: :desc }
scope :chronologically, -> { order created_at: :asc, id: :asc }
scope :ordered_by_activity, -> { order activity_score: :desc }
scope :in_bucket, ->(bucket) { where bucket: bucket }

# FIXME: Compute activity and comment count at write time so it's easier to query for.
scope :left_joins_comments, -> do
left_joins(:messages).merge(Message.left_joins_messageable(:comments))
end
scope :ordered_by_activity, -> do
left_joins_comments.select("bubbles.*, COUNT(comments.id) + bubbles.boost_count AS activity").group(:id).order("activity DESC")
end
scope :ordered_by_comments, -> do
left_joins_comments.select("bubbles.*, COUNT(comments.id) AS comment_count").group(:id).order("comment_count DESC")
end

scope :indexed_by, ->(index) do
case index
when "most_active" then ordered_by_activity
Expand All @@ -34,8 +24,8 @@ class Bubble < ApplicationRecord
end
end

def activity_count
boost_count + messages.comments.size
def rescore
update! activity_score: boost_count + comments_count
end

private
Expand Down
3 changes: 2 additions & 1 deletion app/models/bubble/boostable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ module Bubble::Boostable

def boost!
transaction do
increment! :boost_count
track_event :boosted
increment! :boost_count
rescore
end
end
end
17 changes: 17 additions & 0 deletions app/models/bubble/commentable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Bubble::Commentable
extend ActiveSupport::Concern

included do
scope :ordered_by_comments, -> { order comments_count: :desc }
end

def comment_created
increment! :comments_count
rescore
end

def comment_destroyed
decrement! :comments_count
rescore
end
end
15 changes: 11 additions & 4 deletions app/models/message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ class Message < ApplicationRecord

scope :chronologically, -> { order created_at: :asc, id: :desc }

# FIXME: Will be made redundant when we compute activity and comment count at write time. See commit.
scope :left_joins_messageable, ->(messageable_type) do
joins "LEFT OUTER JOIN #{messageable_type} ON messages.messageable_id = #{messageable_type}.id"
end
after_create :created
after_destroy :destroyed

private
def created
bubble.comment_created if comment?
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We considered this sort of design as well:

class Message < AR
  after_create :captured
  after_destroy :uncaptured

  private
    def captured
      messageable.captured_as(self)
    end

    def uncaptured
      messageable.uncaptured_as(self)
    end
end

class Comment < AR
  def captured_as(message)
    message.bubble.comment_captured
  end

  def uncaptured_as(message)
    message.bubble.comment_uncaptured
  end
end

But it felt premature in that comments are the only kind of messageable (of which there's only two now) that needs to notify the bubble it's been captured.

We can migrate to that design if needed. Doing the simplest thing for now.

end

def destroyed
bubble.comment_destroyed if comment?
end
end
5 changes: 5 additions & 0 deletions db/migrate/20241115234456_add_comments_count_to_bubbles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddCommentsCountToBubbles < ActiveRecord::Migration[8.0]
def change
add_column :bubbles, :comments_count, :integer, null: false, default: 0
end
end
5 changes: 5 additions & 0 deletions db/migrate/20241115234505_add_activity_score_to_bubbles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddActivityScoreToBubbles < ActiveRecord::Migration[8.0]
def change
add_column :bubbles, :activity_score, :integer, null: false, default: 0
end
end
4 changes: 3 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions test/fixtures/bubbles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ logo:
due_on: <%= 3.days.from_now %>
created_at: <%= 1.week.ago %>
boost_count: 5
comments_count: 2
activity_score: 7

layout:
bucket: writebook
creator: david
title: Layout is broken
color: "#698F9C"
created_at: <%= 1.week.ago %>
comments_count: 1
activity_score: 1

text:
bucket: writebook
Expand Down
8 changes: 5 additions & 3 deletions test/models/bubble_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ class BubbleTest < ActiveSupport::TestCase
end

test "boosting" do
assert_difference %w[ bubbles(:logo).boost_count Event.count ], +1 do
bubbles(:logo).boost!
assert_changes "bubbles(:logo).activity_score", +1 do
assert_difference %w[ bubbles(:logo).boost_count Event.count ], +1 do
bubbles(:logo).boost!
end
end
end

Expand All @@ -33,7 +35,7 @@ class BubbleTest < ActiveSupport::TestCase
end

test "ordering by activity" do
bubbles(:layout).update! boost_count: 1_000
bubbles(:layout).tap { |b| b.update!(boost_count: 1_000) }.rescore
assert_equal bubbles(:layout, :logo, :shipping, :text), Bubble.ordered_by_activity
end

Expand Down
14 changes: 14 additions & 0 deletions test/models/comment_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,18 @@ class CommentTest < ActiveSupport::TestCase

assert_includes Comment.search("something rustic"), message.comment
end

test "updating bubble counter" do
assert_changes "bubbles(:logo).activity_score" do
assert_difference "bubbles(:logo).comments_count", 1 do
bubbles(:logo).capture Comment.new(body: "I'd prefer something more rustic")
end
end

assert_changes "bubbles(:logo).activity_score" do
assert_difference "bubbles(:logo).comments_count", -1 do
bubbles(:logo).messages.comments.last.destroy
end
end
end
end