Merge pull request #392 from basecamp/gold-cards

Gold cards
This commit is contained in:
Jorge Manrubia
2025-04-11 10:49:45 +02:00
committed by GitHub
22 changed files with 320 additions and 152 deletions
+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m15.58 16.8-3.58-2.3-3.58 2.3 1.08-4.12-3.29-2.68 4.25-.26 1.54-3.94 1.54 3.94 4.25.26-3.29 2.68m5.5-.68c0-1.11.9-2 2-2v-4c0-1.11-.9-2-2-2h-16a2 2 0 0 0 -2 2v4c1.11 0 2 .9 2 2a2 2 0 0 1 -2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-4a2 2 0 0 1 -2-2z"/></svg>

After

Width:  |  Height:  |  Size: 320 B

-1
View File
@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m12 18.5 7.5 4.5-2-8.5 6.6-5.7-8.7-.8-3.4-8-3.4 8-8.7.8 6.6 5.7-2 8.5z"/></svg>

Before

Width:  |  Height:  |  Size: 148 B

+2
View File
@@ -31,6 +31,7 @@
--lch-blue: 54% 0.15 255;
--lch-blue-light: 95% 0.03 255;
--lch-blue-dark: 80% 0.08 255;
--lch-golden: 83% 0.1128 72.43;
--lch-orange: 70% 0.2 44;
--lch-red: 51% 0.2 31;
--lch-green: 65.59% 0.234 142.49;
@@ -58,6 +59,7 @@
--color-always-black: oklch(var(--lch-always-black));
--color-always-white: oklch(var(--lch-always-white));
--color-container: oklch(var(--lch-light-blue));
--color-golden: oklch(var(--lch-golden));
@media (prefers-color-scheme: dark) {
--lch-black: 100% 0 0;
+11 -6
View File
@@ -97,6 +97,17 @@
}
}
.card--golden {
--border-color: var(--color-bg) !important;
background-color: var(--color-bg);
background-image: linear-gradient(90deg, oklch(var(--lch-golden) / 0.5) 0%, oklch(var(--lch-golden) / 0.1) 50%, oklch(var(--lch-golden) / 0.75) 100%);
box-shadow:
0 0 0.5em 0.2em var(--color-golden),
0 0 1em 0.4em var(--color-golden) !important;
outline: 1px solid var(--color-golden);
}
.card__actions {
position: absolute;
inset: var(--actions-block-inset) auto auto calc(var(--actions-inline-inset) * -1);
@@ -247,12 +258,6 @@
display: inline-flex;
margin-block: calc(var(--block-space) * -1) calc(var(--block-space) * -0.33);
padding: var(--padding-block) var(--padding-inline);
&:has(.card__star-input:checked) {
.card {
outline: 4px solid var(--color-negative);
}
}
}
.card__container--pointing {
+1 -1
View File
@@ -38,6 +38,7 @@
.icon--everyone { --svg: url("everyone.svg "); }
.icon--filter { --svg: url("filter.svg "); }
.icon--globe { --svg: url("globe.svg "); }
.icon--golden-ticket { --svg: url("golden-ticket.svg "); }
.icon--home { --svg: url("home.svg "); }
.icon--logout { --svg: url("logout.svg "); }
.icon--menu { --svg: url("menu.svg "); }
@@ -61,7 +62,6 @@
.icon--rename { --svg: url("rename.svg "); }
.icon--settings { --svg: url("settings.svg "); }
.icon--share { --svg: url("share.svg "); }
.icon--star { --svg: url("star.svg "); }
.icon--tag { --svg: url("tag.svg "); }
.icon--thumb-up { --svg: url("thumb-up.svg "); }
.icon--trash { --svg: url("trash.svg "); }
@@ -0,0 +1,13 @@
class Cards::GoldnessesController < ApplicationController
include CardScoped
def create
@card.gild
redirect_to @card
end
def destroy
@card.ungild
redirect_to @card
end
end
+4 -3
View File
@@ -1,6 +1,7 @@
class Card < ApplicationRecord
include Assignable, Boostable, Colored, Commentable, Engageable, Eventable,
Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged, Statuses, Taggable, Watchable
include Assignable, Boostable, Colored, Commentable, Engageable, Eventable, Golden,
Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged,
Statuses, Taggable, Watchable
belongs_to :collection, touch: true
belongs_to :creator, class_name: "User", default: -> { Current.user }
@@ -34,7 +35,7 @@ class Card < ApplicationRecord
scope :by_engagement_status, ->(status) do
case status.to_s
when "considering" then considering
when "doing" then doing
when "doing" then doing.with_golden_first
end
end
+23
View File
@@ -0,0 +1,23 @@
module Card::Golden
extend ActiveSupport::Concern
included do
scope :golden, -> { joins(:goldness) }
has_one :goldness, dependent: :destroy, class_name: "Card::Goldness"
scope :with_golden_first, -> { left_outer_joins(:goldness).prepend_order("card_goldnesses.id IS NULL") }
end
def golden?
goldness.present?
end
def gild
create_goldness! unless golden?
end
def ungild
goldness&.destroy
end
end
+3
View File
@@ -0,0 +1,3 @@
class Card::Goldness < ApplicationRecord
belongs_to :card, touch: true
end
+11
View File
@@ -0,0 +1,11 @@
<% if card.golden? %>
<%= button_to card_goldness_path(card), method: :delete, class: "btn btn--reversed" do %>
<%= icon_tag "golden-ticket" %>
<span class="for-screen-reader">Demote to normal</span>
<% end %>
<% else %>
<%= button_to card_goldness_path(card), class: "btn" do %>
<%= icon_tag "golden-ticket" %>
<span class="for-screen-reader">Promote to golden</span>
<% end %>
<% end %>
+1 -1
View File
@@ -1,5 +1,5 @@
<% cache card do %>
<article class="card shadow border flex flex-column position-relative txt-align-start border-radius"
<article class="card shadow border flex flex-column position-relative txt-align-start border-radius <%= 'card--golden' if card.golden? %>"
style="--card-color: <%= card.color %>; view-transition-name: <%= dom_id(card, :ticket) %>;"
id="<%= dom_id(card, :ticket) %>">
<header class="card__header flex align-center gap min-width">
+1 -1
View File
@@ -1,5 +1,5 @@
<% cache [ card ] do %>
<article class="card shadow border flex flex-column position-relative txt-align-start full-width border-radius"
<article class="card shadow border flex flex-column position-relative txt-align-start full-width border-radius <%= 'card--golden' if card.golden? %>"
style="--card-color: <%= card.color %>; view-transition-name: <%= dom_id(card, :ticket) %>;"
id="<%= dom_id(card, :ticket) %>">
<header class="card__header flex align-center gap min-width">
+1 -5
View File
@@ -51,11 +51,7 @@
<%= render "cards/display/perma", card: @card %>
<div class="card__actions flex flex-column gap-half">
<button class="car__star-button btn">
<%= icon_tag "star" %>
<span class="for-screen-reader">Star this card</span>
<input type="checkbox" class="card__star-input">
</button>
<%= render "cards/golden_toggle", card: @card if @card.doing? %>
<%= render "cards/image", card: @card %>
<%= button_to collection_card_path(@card.collection, @card),
+1
View File
@@ -22,6 +22,7 @@ Rails.application.routes.draw do
resource :reading
resource :recover
resource :watch
resource :goldness
resources :assignments
resources :boosts
@@ -0,0 +1,9 @@
class CreateCardGoldnesses < ActiveRecord::Migration[8.1]
def change
create_table :card_goldnesses do |t|
t.references :card, null: false, foreign_key: true, index: { unique: true }
t.timestamps
end
end
end
Generated
+9 -1
View File
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.1].define(version: 2025_04_09_201424) do
ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
create_table "accesses", force: :cascade do |t|
t.integer "collection_id", null: false
t.datetime "created_at", null: false
@@ -102,6 +102,13 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_09_201424) do
t.index ["card_id"], name: "index_card_engagements_on_card_id"
end
create_table "card_goldnesses", force: :cascade do |t|
t.integer "card_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["card_id"], name: "index_card_goldnesses_on_card_id", unique: true
end
create_table "cards", force: :cascade do |t|
t.float "activity_score", default: 0.0, null: false
t.datetime "activity_score_at"
@@ -333,6 +340,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_09_201424) do
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "card_goldnesses", "cards"
add_foreign_key "cards", "workflow_stages", column: "stage_id"
add_foreign_key "closures", "cards"
add_foreign_key "closures", "users"
+156 -132
View File
@@ -21,7 +21,7 @@ columns:
default_function:
collation:
comment:
- &23 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
- &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
name: collection_id
cast_type: *1
@@ -341,7 +341,7 @@ columns:
- *5
- *19
- *20
- &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
- &21 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
name: card_id
cast_type: *1
@@ -367,16 +367,21 @@ columns:
comment:
- *6
- *9
card_goldnesses:
- *5
- *21
- *6
- *9
cards:
- *5
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
name: activity_score
cast_type: &21 !ruby/object:ActiveModel::Type::Float
cast_type: &22 !ruby/object:ActiveModel::Type::Float
precision:
scale:
limit:
sql_type_metadata: &22 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
sql_type_metadata: &23 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
sql_type: float
type: :float
limit:
@@ -400,8 +405,8 @@ columns:
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
name: activity_score_order
cast_type: *21
sql_type_metadata: *22
cast_type: *22
sql_type_metadata: *23
'null': false
default: 0.0
default_function:
@@ -417,7 +422,7 @@ columns:
default_function:
collation:
comment:
- *23
- *24
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
name: comments_count
@@ -525,7 +530,7 @@ columns:
- *9
closures:
- *5
- *24
- *21
- *6
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
@@ -593,7 +598,7 @@ columns:
collation:
comment:
collections_filters:
- *23
- *24
- *18
comments:
- *5
@@ -619,7 +624,7 @@ columns:
default_function:
collation:
comment:
- *24
- *21
- *6
- *25
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
@@ -712,7 +717,7 @@ columns:
comment:
messages:
- *5
- *24
- *21
- *6
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
@@ -737,7 +742,7 @@ columns:
- *9
notifications:
- *5
- *24
- *21
- *6
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
@@ -783,7 +788,7 @@ columns:
- *30
pins:
- *5
- *24
- *21
- *6
- *9
- *30
@@ -869,7 +874,7 @@ columns:
- *30
taggings:
- *5
- *24
- *21
- *6
- *31
- *9
@@ -927,7 +932,7 @@ columns:
- *9
watches:
- *5
- *24
- *21
- *6
- *9
- *30
@@ -984,6 +989,7 @@ primary_keys:
assigners_filters:
assignments: id
card_engagements: id
card_goldnesses: id
cards: id
closure_reasons: id
closures: id
@@ -1020,6 +1026,7 @@ data_sources:
assigners_filters: true
assignments: true
card_engagements: true
card_goldnesses: true
cards: true
closure_reasons: true
closures: true
@@ -1048,10 +1055,9 @@ indexes:
accesses:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: accesses
name: index_accesses_on_collection_id_and_user_id
unique: true
name: index_accesses_on_user_id
unique: false
columns:
- collection_id
- user_id
lengths: {}
orders: {}
@@ -1081,9 +1087,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: accesses
name: index_accesses_on_user_id
unique: false
name: index_accesses_on_collection_id_and_user_id
unique: true
columns:
- collection_id
- user_id
lengths: {}
orders: {}
@@ -1303,10 +1310,9 @@ indexes:
assignments:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: assignments
name: index_assignments_on_assignee_id_and_card_id
unique: true
name: index_assignments_on_card_id
unique: false
columns:
- assignee_id
- card_id
lengths: {}
orders: {}
@@ -1320,9 +1326,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: assignments
name: index_assignments_on_card_id
unique: false
name: index_assignments_on_assignee_id_and_card_id
unique: true
columns:
- assignee_id
- card_id
lengths: {}
orders: {}
@@ -1351,7 +1358,57 @@ indexes:
nulls_not_distinct:
comment:
valid: true
card_goldnesses:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: card_goldnesses
name: index_card_goldnesses_on_card_id
unique: true
columns:
- card_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
cards:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: cards
name: index_cards_on_stage_id
unique: false
columns:
- stage_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: cards
name: index_cards_on_last_active_at_and_status
unique: false
columns:
- last_active_at
- status
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: cards
name: index_cards_on_collection_id
@@ -1384,39 +1441,6 @@ indexes:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: cards
name: index_cards_on_last_active_at_and_status
unique: false
columns:
- last_active_at
- status
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: cards
name: index_cards_on_stage_id
unique: false
columns:
- stage_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
closure_reasons:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: closure_reasons
@@ -1435,6 +1459,22 @@ indexes:
comment:
valid: true
closures:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: closures
name: index_closures_on_user_id
unique: false
columns:
- user_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: closures
name: index_closures_on_card_id
@@ -1468,29 +1508,13 @@ indexes:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: closures
name: index_closures_on_user_id
unique: false
columns:
- user_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
collections:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: collections
name: index_collections_on_account_id
name: index_collections_on_workflow_id
unique: false
columns:
- account_id
- workflow_id
lengths: {}
orders: {}
opclasses: {}
@@ -1519,10 +1543,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: collections
name: index_collections_on_workflow_id
name: index_collections_on_account_id
unique: false
columns:
- workflow_id
- account_id
lengths: {}
orders: {}
opclasses: {}
@@ -1536,10 +1560,10 @@ indexes:
collections_filters:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: collections_filters
name: index_collections_filters_on_collection_id
name: index_collections_filters_on_filter_id
unique: false
columns:
- collection_id
- filter_id
lengths: {}
orders: {}
opclasses: {}
@@ -1552,10 +1576,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: collections_filters
name: index_collections_filters_on_filter_id
name: index_collections_filters_on_collection_id
unique: false
columns:
- filter_id
- collection_id
lengths: {}
orders: {}
opclasses: {}
@@ -1602,22 +1626,6 @@ indexes:
valid: true
event_summaries: []
events:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: events
name: index_events_on_card_id
unique: false
columns:
- card_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: events
name: index_events_on_summary_id_and_action
@@ -1651,6 +1659,22 @@ indexes:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: events
name: index_events_on_card_id
unique: false
columns:
- card_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
filters:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: filters
@@ -1736,22 +1760,6 @@ indexes:
comment:
valid: true
messages:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: messages
name: index_messages_on_card_id
unique: false
columns:
- card_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: messages
name: index_messages_on_messageable
@@ -1769,10 +1777,9 @@ indexes:
nulls_not_distinct:
comment:
valid: true
notifications:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: notifications
name: index_notifications_on_card_id
table: messages
name: index_messages_on_card_id
unique: false
columns:
- card_id
@@ -1786,6 +1793,7 @@ indexes:
nulls_not_distinct:
comment:
valid: true
notifications:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: notifications
name: index_notifications_on_user_id
@@ -1855,13 +1863,28 @@ indexes:
nulls_not_distinct:
comment:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: notifications
name: index_notifications_on_card_id
unique: false
columns:
- card_id
lengths: {}
orders: {}
opclasses: {}
where:
type:
using:
include:
nulls_not_distinct:
comment:
valid: true
pins:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: pins
name: index_pins_on_card_id_and_user_id
unique: true
name: index_pins_on_user_id
unique: false
columns:
- card_id
- user_id
lengths: {}
orders: {}
@@ -1891,9 +1914,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: pins
name: index_pins_on_user_id
unique: false
name: index_pins_on_card_id_and_user_id
unique: true
columns:
- card_id
- user_id
lengths: {}
orders: {}
@@ -1959,10 +1983,9 @@ indexes:
taggings:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: taggings
name: index_taggings_on_card_id_and_tag_id
unique: true
name: index_taggings_on_tag_id
unique: false
columns:
- card_id
- tag_id
lengths: {}
orders: {}
@@ -1976,9 +1999,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: taggings
name: index_taggings_on_tag_id
unique: false
name: index_taggings_on_card_id_and_tag_id
unique: true
columns:
- card_id
- tag_id
lengths: {}
orders: {}
@@ -2076,10 +2100,10 @@ indexes:
watches:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: watches
name: index_watches_on_card_id
name: index_watches_on_user_id
unique: false
columns:
- card_id
- user_id
lengths: {}
orders: {}
opclasses: {}
@@ -2092,10 +2116,10 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: watches
name: index_watches_on_user_id
name: index_watches_on_card_id
unique: false
columns:
- user_id
- card_id
lengths: {}
orders: {}
opclasses: {}
@@ -2140,4 +2164,4 @@ indexes:
nulls_not_distinct:
comment:
valid: true
version: 20250409201424
version: 20250410141409
+16
View File
@@ -0,0 +1,16 @@
module ActiveRecordRelationPrependOrder
extend ActiveSupport::Concern
included do
def prepend_order(*args)
new_orders = args.flatten.map { |arg| arg.is_a?(String) ? arg : arg.to_sql }
spawn.tap do |relation|
relation.order_values = new_orders + order_values
end
end
end
end
ActiveRecord::Relation.include(ActiveRecordRelationPrependOrder)
ActiveRecord::AssociationRelation.include(ActiveRecordRelationPrependOrder)
@@ -0,0 +1,27 @@
require "test_helper"
class Cards::GoldnessesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in_as :kevin
end
test "create" do
card = cards(:text)
assert_changes -> { card.reload.golden? }, from: false, to: true do
post card_goldness_url(card)
end
assert_redirected_to collection_card_url(card.collection, card)
end
test "destroy" do
card = cards(:logo)
assert_changes -> { card.reload.golden? }, from: true, to: false do
delete card_goldness_url(card)
end
assert_redirected_to collection_card_url(card.collection, card)
end
end
+1 -1
View File
@@ -1,2 +1,2 @@
logo_engagement:
logo:
card: logo
+2
View File
@@ -0,0 +1,2 @@
logo:
card: logo
+27
View File
@@ -0,0 +1,27 @@
require "test_helper"
class Card::GoldenTest < ActiveSupport::TestCase
setup do
Current.session = sessions(:david)
end
test "check whether a card is golden" do
assert cards(:logo).golden?
assert_not cards(:text).golden?
end
test "promote and demote from golden" do
assert_changes -> { cards(:text).reload.golden? }, to: true do
cards(:text).gild
end
assert_changes -> { cards(:logo).reload.golden? }, to: false do
cards(:logo).ungild
end
end
test "scopes" do
assert_includes Card.golden, cards(:logo)
assert_not_includes Card.golden, cards(:text)
end
end