Merge pull request #2416 from basecamp/introduce-reactable
Make `Reaction` polymorphic with `reactable` association
This commit is contained in:
@@ -4,7 +4,7 @@ class Comment < ApplicationRecord
|
|||||||
belongs_to :account, default: -> { card.account }
|
belongs_to :account, default: -> { card.account }
|
||||||
belongs_to :card, touch: true
|
belongs_to :card, touch: true
|
||||||
belongs_to :creator, class_name: "User", default: -> { Current.user }
|
belongs_to :creator, class_name: "User", default: -> { Current.user }
|
||||||
has_many :reactions, -> { order(:created_at) }, dependent: :delete_all
|
has_many :reactions, -> { order(:created_at) }, as: :reactable, dependent: :delete_all
|
||||||
|
|
||||||
has_rich_text :body
|
has_rich_text :body
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
class Reaction < ApplicationRecord
|
class Reaction < ApplicationRecord
|
||||||
belongs_to :account, default: -> { comment.account }
|
belongs_to :account, default: -> { reactable.account }
|
||||||
belongs_to :comment, touch: true
|
belongs_to :reactable, polymorphic: true, touch: true
|
||||||
belongs_to :reacter, class_name: "User", default: -> { Current.user }
|
belongs_to :reacter, class_name: "User", default: -> { Current.user }
|
||||||
|
|
||||||
scope :ordered, -> { order(:created_at) }
|
scope :ordered, -> { order(:created_at) }
|
||||||
@@ -11,6 +11,6 @@ class Reaction < ApplicationRecord
|
|||||||
|
|
||||||
private
|
private
|
||||||
def register_card_activity
|
def register_card_activity
|
||||||
comment.card.touch_last_active_at
|
reactable.card.touch_last_active_at
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
class: [ "txt-small", { "txt-medium": reaction.all_emoji? } ],
|
class: [ "txt-small", { "txt-medium": reaction.all_emoji? } ],
|
||||||
data: { action: "click->reaction-delete#reveal keydown.enter->reaction-delete#reveal:prevent", reaction_delete_target: "content" } %>
|
data: { action: "click->reaction-delete#reveal keydown.enter->reaction-delete#reveal:prevent", reaction_delete_target: "content" } %>
|
||||||
|
|
||||||
<%= button_to card_comment_reaction_path(reaction.comment.card, reaction.comment, reaction),
|
<%= button_to card_comment_reaction_path(reaction.reactable.card, reaction.reactable, reaction),
|
||||||
method: :delete,
|
method: :delete,
|
||||||
class: "reaction__delete btn btn--negative flex-item-justify-end",
|
class: "reaction__delete btn btn--negative flex-item-justify-end",
|
||||||
data: { action: "reaction-delete#perform", reaction_delete_target: "button" } do %>
|
data: { action: "reaction-delete#perform", reaction_delete_target: "button" } do %>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
json.cache! reaction do
|
json.cache! reaction do
|
||||||
json.(reaction, :id, :content)
|
json.(reaction, :id, :content)
|
||||||
json.reacter reaction.reacter, partial: "users/user", as: :user
|
json.reacter reaction.reacter, partial: "users/user", as: :user
|
||||||
json.url card_comment_reaction_url(reaction.comment.card, reaction.comment, reaction)
|
json.url card_comment_reaction_url(reaction.reactable.card, reaction.reactable, reaction)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
class MakeReactionsPolymorphic < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
add_column :reactions, :reactable_type, :string
|
||||||
|
add_column :reactions, :reactable_id, :uuid
|
||||||
|
|
||||||
|
reversible do |dir|
|
||||||
|
dir.up do
|
||||||
|
execute <<~SQL
|
||||||
|
UPDATE reactions SET reactable_type = 'Comment', reactable_id = comment_id
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
dir.down do
|
||||||
|
execute <<~SQL
|
||||||
|
UPDATE reactions SET comment_id = reactable_id WHERE reactable_type = 'Comment'
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
change_column_null :reactions, :reactable_type, false
|
||||||
|
change_column_null :reactions, :reactable_id, false
|
||||||
|
|
||||||
|
remove_column :reactions, :comment_id, :uuid
|
||||||
|
|
||||||
|
add_index :reactions, [:reactable_type, :reactable_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
Generated
+4
-3
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.2].define(version: 2025_12_24_092315) do
|
ActiveRecord::Schema[8.2].define(version: 2026_01_21_155752) do
|
||||||
create_table "accesses", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
create_table "accesses", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||||
t.datetime "accessed_at"
|
t.datetime "accessed_at"
|
||||||
t.uuid "account_id", null: false
|
t.uuid "account_id", null: false
|
||||||
@@ -412,13 +412,14 @@ ActiveRecord::Schema[8.2].define(version: 2025_12_24_092315) do
|
|||||||
|
|
||||||
create_table "reactions", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
create_table "reactions", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||||
t.uuid "account_id", null: false
|
t.uuid "account_id", null: false
|
||||||
t.uuid "comment_id", null: false
|
|
||||||
t.string "content", limit: 16, null: false
|
t.string "content", limit: 16, null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
|
t.uuid "reactable_id", null: false
|
||||||
|
t.string "reactable_type", null: false
|
||||||
t.uuid "reacter_id", null: false
|
t.uuid "reacter_id", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["account_id"], name: "index_reactions_on_account_id"
|
t.index ["account_id"], name: "index_reactions_on_account_id"
|
||||||
t.index ["comment_id"], name: "index_reactions_on_comment_id"
|
t.index ["reactable_type", "reactable_id"], name: "index_reactions_on_reactable_type_and_reactable_id"
|
||||||
t.index ["reacter_id"], name: "index_reactions_on_reacter_id"
|
t.index ["reacter_id"], name: "index_reactions_on_reacter_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.2].define(version: 2025_12_24_092315) do
|
ActiveRecord::Schema[8.2].define(version: 2026_01_21_155752) do
|
||||||
create_table "accesses", id: :uuid, force: :cascade do |t|
|
create_table "accesses", id: :uuid, force: :cascade do |t|
|
||||||
t.datetime "accessed_at"
|
t.datetime "accessed_at"
|
||||||
t.uuid "account_id", null: false
|
t.uuid "account_id", null: false
|
||||||
@@ -412,13 +412,14 @@ ActiveRecord::Schema[8.2].define(version: 2025_12_24_092315) do
|
|||||||
|
|
||||||
create_table "reactions", id: :uuid, force: :cascade do |t|
|
create_table "reactions", id: :uuid, force: :cascade do |t|
|
||||||
t.uuid "account_id", null: false
|
t.uuid "account_id", null: false
|
||||||
t.uuid "comment_id", null: false
|
|
||||||
t.string "content", limit: 16, null: false
|
t.string "content", limit: 16, null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
|
t.uuid "reactable_id", null: false
|
||||||
|
t.string "reactable_type", limit: 255, null: false
|
||||||
t.uuid "reacter_id", null: false
|
t.uuid "reacter_id", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["account_id"], name: "index_reactions_on_account_id"
|
t.index ["account_id"], name: "index_reactions_on_account_id"
|
||||||
t.index ["comment_id"], name: "index_reactions_on_comment_id"
|
t.index ["reactable_type", "reactable_id"], name: "index_reactions_on_reactable_type_and_reactable_id"
|
||||||
t.index ["reacter_id"], name: "index_reactions_on_reacter_id"
|
t.index ["reacter_id"], name: "index_reactions_on_reacter_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -2,12 +2,12 @@ kevin:
|
|||||||
id: <%= ActiveRecord::FixtureSet.identify("kevin_reaction", :uuid) %>
|
id: <%= ActiveRecord::FixtureSet.identify("kevin_reaction", :uuid) %>
|
||||||
account: 37s_uuid
|
account: 37s_uuid
|
||||||
content: "👍"
|
content: "👍"
|
||||||
comment: logo_agreement_jz_uuid
|
reactable: logo_agreement_jz_uuid (Comment)
|
||||||
reacter: kevin_uuid
|
reacter: kevin_uuid
|
||||||
|
|
||||||
david:
|
david:
|
||||||
id: <%= ActiveRecord::FixtureSet.identify("david_reaction", :uuid) %>
|
id: <%= ActiveRecord::FixtureSet.identify("david_reaction", :uuid) %>
|
||||||
account: 37s_uuid
|
account: 37s_uuid
|
||||||
content: "👍"
|
content: "👍"
|
||||||
comment: logo_agreement_jz_uuid
|
reactable: logo_agreement_jz_uuid (Comment)
|
||||||
reacter: david_uuid
|
reacter: david_uuid
|
||||||
|
|||||||
Reference in New Issue
Block a user