rails_badgeable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +83 -0
- data/Rakefile +6 -0
- data/app/models/concerns/rails_badgeable/has_badges.rb +16 -0
- data/app/models/rails_badgeable/badge.rb +21 -0
- data/app/models/rails_badgeable/badge_assignment.rb +12 -0
- data/db/migrate/20250131000000_create_rails_badgeable_tables.rb +35 -0
- data/lib/generators/rails_badgeable/alias/USAGE +34 -0
- data/lib/generators/rails_badgeable/alias/alias_generator.rb +15 -0
- data/lib/generators/rails_badgeable/alias/templates/badgeable.rb +11 -0
- data/lib/rails_badgeable/engine.rb +5 -0
- data/lib/rails_badgeable/version.rb +3 -0
- data/lib/rails_badgeable.rb +6 -0
- data/lib/tasks/rails_badgeable_tasks.rake +4 -0
- data/llms.txt +294 -0
- metadata +84 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: fdf33a8abbd83c9d997979dfb8e2a54db42bcb6d93d3330da510cfc25af16365
|
|
4
|
+
data.tar.gz: 718c6e9c4129ee455a4e1c8da84e7d8a09c5f417f0562ba5d51057bcba8752b1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 49607b5870779c82353a54f74712ece2a843f7eb0e1be2185615c1576430edf7316c1f323a7c7f571f411dc851825fbfd9ec3c130e45a7c585a663959f981afe
|
|
7
|
+
data.tar.gz: 977e2b6bdae4996c37a663679982f4ca223e9d794559fff527a230ac13031dc73abcf53294d78402f81eb7571c3b6dee6e1911a511338fb98b764867bc29c8ef
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright aric.zheng
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# rails_badgeable
|
|
2
|
+
|
|
3
|
+
A lightweight, reusable Rails Engine for adding badges to any ActiveRecord model via polymorphic many-to-many relationships.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'rails_badgeable'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then run:
|
|
14
|
+
```bash
|
|
15
|
+
rails rails_badgeable:install:migrations
|
|
16
|
+
rails db:migrate
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Include the concern in any model:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
class Post < ApplicationRecord
|
|
25
|
+
include RailsBadgeable::HasBadges
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
post = Post.create(title: "Hello")
|
|
29
|
+
# 创建或查找一个名为 "Important" 的 badge
|
|
30
|
+
badge = RailsBadgeable::Badge.find_or_create_by(name: "Important")
|
|
31
|
+
|
|
32
|
+
# 将 badge 分配给 post
|
|
33
|
+
post.badges << badge
|
|
34
|
+
|
|
35
|
+
# 查询:这个 badge 分配给了哪些 posts?
|
|
36
|
+
# 返回所有带有 "Important" badge 的 Post 记录
|
|
37
|
+
badge.assigned_to(Post) # => [post]
|
|
38
|
+
|
|
39
|
+
# 查询:Post 模型使用过哪些 badges?
|
|
40
|
+
# 返回所有曾经分配给 Post 的 badges(排除从未使用过的)
|
|
41
|
+
RailsBadgeable::Badge.for_model(Post) # => [badge]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Using Short Alias (Optional)
|
|
45
|
+
|
|
46
|
+
If you prefer using `Badge` instead of `RailsBadgeable::Badge`, use the generator to create an alias initializer:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
rails generate rails_badgeable:alias
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This creates `config/initializers/badgeable.rb` with the following:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
Badge = RailsBadgeable::Badge unless defined?(Badge)
|
|
56
|
+
BadgeAssignment = RailsBadgeable::BadgeAssignment unless defined?(BadgeAssignment)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then you can use the short form:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
# Instead of RailsBadgeable::Badge
|
|
63
|
+
Badge.find_or_create_by(name: "Important")
|
|
64
|
+
|
|
65
|
+
# Instead of RailsBadgeable::BadgeAssignment
|
|
66
|
+
BadgeAssignment.all
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Available Methods
|
|
70
|
+
|
|
71
|
+
### Instance Methods (on a Badge object)
|
|
72
|
+
|
|
73
|
+
- `badge.assigned_to(klass)` - Returns all records of the given class that have this badge
|
|
74
|
+
|
|
75
|
+
### Class Methods (on Badge class)
|
|
76
|
+
|
|
77
|
+
- `RailsBadgeable::Badge.for_model(klass)` - Returns all badges ever used on the given model class
|
|
78
|
+
|
|
79
|
+
### Model Methods (on models with HasBadges)
|
|
80
|
+
|
|
81
|
+
- `post.badges` - Returns all badges assigned to this post
|
|
82
|
+
- `post.badges << badge` - Assign a badge to this post
|
|
83
|
+
- `post.badges.destroy(badge)` - Remove a badge from this post
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module RailsBadgeable
|
|
2
|
+
module HasBadges
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
has_many :rails_badgeable_assignments,
|
|
7
|
+
as: :assignable,
|
|
8
|
+
class_name: "RailsBadgeable::BadgeAssignment",
|
|
9
|
+
dependent: :destroy
|
|
10
|
+
|
|
11
|
+
has_many :badges,
|
|
12
|
+
through: :rails_badgeable_assignments,
|
|
13
|
+
class_name: "RailsBadgeable::Badge"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module RailsBadgeable
|
|
2
|
+
class Badge < ApplicationRecord
|
|
3
|
+
self.table_name = "rails_badgeable_badges"
|
|
4
|
+
|
|
5
|
+
has_many :assignments, class_name: "RailsBadgeable::BadgeAssignment", dependent: :destroy
|
|
6
|
+
|
|
7
|
+
validates :name, presence: true, uniqueness: true
|
|
8
|
+
|
|
9
|
+
# Returns all associated records of the given class that have this badge
|
|
10
|
+
def assigned_to(klass)
|
|
11
|
+
assignable_ids = assignments.where(assignable_type: klass.base_class.name).pluck(:assignable_id)
|
|
12
|
+
klass.where(id: assignable_ids)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Class method: Returns all badges ever used on the given model class
|
|
16
|
+
def self.for_model(klass)
|
|
17
|
+
badge_ids = BadgeAssignment.where(assignable_type: klass.base_class.name).distinct.pluck(:badge_id)
|
|
18
|
+
where(id: badge_ids)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module RailsBadgeable
|
|
2
|
+
class BadgeAssignment < ApplicationRecord
|
|
3
|
+
self.table_name = "rails_badgeable_assignments"
|
|
4
|
+
|
|
5
|
+
belongs_to :badge, class_name: "RailsBadgeable::Badge"
|
|
6
|
+
belongs_to :assignable, polymorphic: true
|
|
7
|
+
|
|
8
|
+
validates :badge, presence: true
|
|
9
|
+
validates :assignable, presence: true
|
|
10
|
+
validates :badge_id, uniqueness: { scope: [:assignable_type, :assignable_id] }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateRailsBadgeableTables < ActiveRecord::Migration[6.0]
|
|
4
|
+
def change
|
|
5
|
+
# Create badges table
|
|
6
|
+
# To add custom fields to badges, add columns here, e.g.:
|
|
7
|
+
# t.string :color, default: '#007bff'
|
|
8
|
+
# t.string :icon
|
|
9
|
+
create_table :rails_badgeable_badges do |t|
|
|
10
|
+
t.string :name, null: false
|
|
11
|
+
t.text :description
|
|
12
|
+
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :rails_badgeable_badges, :name, unique: true
|
|
17
|
+
|
|
18
|
+
# Create join table for polymorphic associations
|
|
19
|
+
# To add custom fields to assignments, add columns here, e.g.:
|
|
20
|
+
# t.string :reason
|
|
21
|
+
# t.references :granted_by, foreign_key: { to_table: :users }
|
|
22
|
+
create_table :rails_badgeable_assignments do |t|
|
|
23
|
+
t.references :badge, null: false, foreign_key: { to_table: :rails_badgeable_badges }
|
|
24
|
+
t.references :assignable, polymorphic: true, null: false, index: false
|
|
25
|
+
|
|
26
|
+
t.timestamps
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Custom composite index with short name
|
|
30
|
+
add_index :rails_badgeable_assignments,
|
|
31
|
+
[:badge_id, :assignable_type, :assignable_id],
|
|
32
|
+
unique: true,
|
|
33
|
+
name: "index_badge_assignments"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Creates a short alias initializer for RailsBadgeable models.
|
|
3
|
+
|
|
4
|
+
This allows you to use `Badge` instead of `RailsBadgeable::Badge`
|
|
5
|
+
and `BadgeAssignment` instead of `RailsBadgeable::BadgeAssignment`.
|
|
6
|
+
|
|
7
|
+
The created initializer uses `unless defined?` guards to prevent
|
|
8
|
+
redefinition warnings if these constants already exist in your application.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
rails generate rails_badgeable:alias
|
|
12
|
+
|
|
13
|
+
This will create:
|
|
14
|
+
config/initializers/badgeable.rb
|
|
15
|
+
|
|
16
|
+
Usage After Installation:
|
|
17
|
+
# Before (full namespace required):
|
|
18
|
+
RailsBadgeable::Badge.find_or_create_by(name: "Important")
|
|
19
|
+
RailsBadgeable::BadgeAssignment.all
|
|
20
|
+
|
|
21
|
+
# After (short alias available):
|
|
22
|
+
Badge.find_or_create_by(name: "Important")
|
|
23
|
+
BadgeAssignment.all
|
|
24
|
+
|
|
25
|
+
To Remove:
|
|
26
|
+
Simply delete the generated file:
|
|
27
|
+
rm config/initializers/badgeable.rb
|
|
28
|
+
|
|
29
|
+
Then restart your server to use the full namespace again.
|
|
30
|
+
|
|
31
|
+
Notes:
|
|
32
|
+
- This is completely optional - you can always use the full namespace
|
|
33
|
+
- The generator will not overwrite existing files (use --force to override)
|
|
34
|
+
- Restart your server after running this generator
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsBadgeable
|
|
4
|
+
module Generators
|
|
5
|
+
class AliasGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
|
7
|
+
|
|
8
|
+
desc 'Creates a short alias initializer for RailsBadgeable models.'
|
|
9
|
+
|
|
10
|
+
def create_alias_initializer
|
|
11
|
+
template 'badgeable.rb', 'config/initializers/badgeable.rb'
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Short alias for RailsBadgeable models
|
|
4
|
+
# This allows you to use `Badge` instead of `RailsBadgeable::Badge`
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# Badge.find_or_create_by(name: "Important")
|
|
8
|
+
# BadgeAssignment.all
|
|
9
|
+
|
|
10
|
+
Badge = RailsBadgeable::Badge unless defined?(Badge)
|
|
11
|
+
BadgeAssignment = RailsBadgeable::BadgeAssignment unless defined?(BadgeAssignment)
|
data/llms.txt
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Rails Badgeable
|
|
2
|
+
|
|
3
|
+
> Rails Badgeable is a lightweight, reusable Rails Engine that enables any ActiveRecord model to associate with a finite set of predefined badges via polymorphic many-to-many relationships.
|
|
4
|
+
|
|
5
|
+
It provides a clean, namespace-isolated way to add badge functionality to your Rails applications without polluting your models or database schema. The engine uses standard Rails conventions and is fully compatible with Rails 6.0+.
|
|
6
|
+
|
|
7
|
+
**Important notes for AI agents:**
|
|
8
|
+
- This is a Rails Engine, not a mountable engine (no routes, controllers, or views)
|
|
9
|
+
- All models are namespaced under `RailsBadgeable` module
|
|
10
|
+
- Table names are explicitly set to avoid conflicts: `rails_badgeable_badges` and `rails_badgeable_assignments`
|
|
11
|
+
- The engine uses polymorphic associations, allowing badges to be assigned to ANY model
|
|
12
|
+
- An optional generator is available for creating short aliases (e.g., `Badge` instead of `RailsBadgeable::Badge`)
|
|
13
|
+
|
|
14
|
+
## Documentation
|
|
15
|
+
|
|
16
|
+
- [GitHub Repository](https://github.com/afeiship/rails_badgeable): Source code and issue tracking
|
|
17
|
+
- [README](README.md): Installation guide and basic usage examples
|
|
18
|
+
- [Requirements](docs/01-requirement.md): Detailed project requirements and design specifications
|
|
19
|
+
|
|
20
|
+
## Key Features
|
|
21
|
+
|
|
22
|
+
- **Polymorphic Associations:** Assign badges to any ActiveRecord model (Post, User, Comment, etc.)
|
|
23
|
+
- **Database-level Constraints:** Unique indexes prevent duplicate badge assignments
|
|
24
|
+
- **Namespace Isolated:** All models under `RailsBadgeable` namespace to avoid conflicts
|
|
25
|
+
- **Explicit Table Names:** No reliance on Rails auto-inflection
|
|
26
|
+
- **Optional Short Aliases:** Generator for `Badge` and `BadgeAssignment` aliases
|
|
27
|
+
- **Rails 6.0+ Compatible:** Works with modern Rails versions
|
|
28
|
+
- **Zero Configuration:** Works out of the box after migration
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Add to your Gemfile:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
gem 'rails_badgeable'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Run migrations:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
rails rails_badgeable:install:migrations
|
|
42
|
+
rails db:migrate
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Basic Usage
|
|
46
|
+
|
|
47
|
+
### Include the Concern
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
class Post < ApplicationRecord
|
|
51
|
+
include RailsBadgeable::HasBadges
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class WorkLog < ApplicationRecord
|
|
55
|
+
include RailsBadgeable::HasBadges
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Create and Assign Badges
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
# Create or find a badge
|
|
63
|
+
badge = RailsBadgeable::Badge.find_or_create_by(name: "Important", description: "Important content")
|
|
64
|
+
|
|
65
|
+
# Assign to a post
|
|
66
|
+
post = Post.create(title: "Hello World")
|
|
67
|
+
post.badges << badge
|
|
68
|
+
|
|
69
|
+
# Check if post has the badge
|
|
70
|
+
post.badges.include?(badge) # => true
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Query Methods
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
# Get all posts with a specific badge
|
|
77
|
+
badge.assigned_to(Post)
|
|
78
|
+
# => [#<Post id: 1, ...>, #<Post id: 3, ...>]
|
|
79
|
+
|
|
80
|
+
# Get all badges ever used on Post model
|
|
81
|
+
RailsBadgeable::Badge.for_model(Post)
|
|
82
|
+
# => [#<RailsBadgeable::Badge name: "Important">, ...]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Remove Badges
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# Remove a specific badge
|
|
89
|
+
post.badges.destroy(badge)
|
|
90
|
+
|
|
91
|
+
# Remove all badges
|
|
92
|
+
post.badges.clear
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Optional Short Alias Generator
|
|
96
|
+
|
|
97
|
+
For cleaner code, generate short aliases:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
rails generate rails_badgeable:alias
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This creates `config/initializers/badgeable.rb`:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
Badge = RailsBadgeable::Badge unless defined?(Badge)
|
|
107
|
+
BadgeAssignment = RailsBadgeable::BadgeAssignment unless defined?(BadgeAssignment)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Then use short form:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
Badge.find_or_create_by(name: "Featured")
|
|
114
|
+
BadgeAssignment.all
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Database Schema
|
|
118
|
+
|
|
119
|
+
### badges table
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
create_table :rails_badgeable_badges do |t|
|
|
123
|
+
t.string :name, null: false
|
|
124
|
+
t.text :description
|
|
125
|
+
t.timestamps
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
add_index :rails_badgeable_badges, :name, unique: true
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### assignments table (join table)
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
create_table :rails_badgeable_assignments do |t|
|
|
135
|
+
t.references :badge, null: false, foreign_key: { to_table: :rails_badgeable_badges }
|
|
136
|
+
t.references :assignable, polymorphic: true, null: false
|
|
137
|
+
t.timestamps
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
add_index :rails_badgeable_assignments,
|
|
141
|
+
[:badge_id, :assignable_type, :assignable_id],
|
|
142
|
+
unique: true,
|
|
143
|
+
name: "index_badge_assignments"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Available Methods
|
|
147
|
+
|
|
148
|
+
### Badge Instance Methods
|
|
149
|
+
|
|
150
|
+
- `badge.assigned_to(klass)` - Returns all records of the given class that have this badge
|
|
151
|
+
```ruby
|
|
152
|
+
badge.assigned_to(Post) # => [post1, post2]
|
|
153
|
+
badge.assigned_to(User) # => [user1, user3]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Badge Class Methods
|
|
157
|
+
|
|
158
|
+
- `RailsBadgeable::Badge.for_model(klass)` - Returns all badges ever used on the given model class
|
|
159
|
+
```ruby
|
|
160
|
+
RailsBadgeable::Badge.for_model(Post) # => [badge1, badge2]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Model Methods (with HasBadges concern)
|
|
164
|
+
|
|
165
|
+
- `model.badges` - Returns all badges assigned to this record
|
|
166
|
+
- `model.badges << badge` - Assign a badge to this record
|
|
167
|
+
- `model.badges.delete(badge)` - Remove a specific badge
|
|
168
|
+
- `model.badges.clear` - Remove all badges
|
|
169
|
+
- `model.rails_badgeable_assignments` - Direct access to join records
|
|
170
|
+
|
|
171
|
+
## Advanced Usage
|
|
172
|
+
|
|
173
|
+
### Custom Fields
|
|
174
|
+
|
|
175
|
+
You can add custom fields to badges or assignments via migrations:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
# Add custom fields to badges
|
|
179
|
+
add_column :rails_badgeable_badges, :color, :string, default: '#007bff'
|
|
180
|
+
add_column :rails_badgeable_badges, :icon, :string
|
|
181
|
+
|
|
182
|
+
# Add custom fields to assignments
|
|
183
|
+
add_column :rails_badgeable_assignments, :reason, :text
|
|
184
|
+
add_column :rails_badgeable_assignments, :granted_by_id, :integer
|
|
185
|
+
add_column :rails_badgeable_assignments, :granted_at, :datetime
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Accessing Assignment Data
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
# Get assignment metadata
|
|
192
|
+
assignment = post.rails_badgeable_assignments.find_by(badge_id: 1)
|
|
193
|
+
assignment.reason # => "Community contribution"
|
|
194
|
+
assignment.created_at # => assignment time
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Conditional Scopes
|
|
198
|
+
|
|
199
|
+
Add scopes to your models:
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
class Post < ApplicationRecord
|
|
203
|
+
include RailsBadgeable::HasBadges
|
|
204
|
+
|
|
205
|
+
scope :important, -> { joins(:badges).where(rails_badgeable_badges: { name: 'Important' }) }
|
|
206
|
+
scope :featured, -> { joins(:badges).where(rails_badgeable_badges: { name: 'Featured' }) }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Usage
|
|
210
|
+
Post.important # All posts with "Important" badge
|
|
211
|
+
Post.featured # All posts with "Featured" badge
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## API Example (with dummy app)
|
|
215
|
+
|
|
216
|
+
The included dummy app demonstrates API usage:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Start server
|
|
220
|
+
cd test/dummy
|
|
221
|
+
bin/rails server
|
|
222
|
+
|
|
223
|
+
# API endpoints
|
|
224
|
+
GET /api/badges # List all badges
|
|
225
|
+
POST /api/badges # Create badge
|
|
226
|
+
GET /api/badges/:id # Get badge
|
|
227
|
+
PUT /api/badges/:id # Update badge
|
|
228
|
+
DELETE /api/badges/:id # Delete badge
|
|
229
|
+
GET /api/badges/:id/assigned_to?model_type=Post # Get records with badge
|
|
230
|
+
|
|
231
|
+
GET /api/posts # List posts
|
|
232
|
+
POST /api/posts # Create post
|
|
233
|
+
GET /api/posts/:id # Get post (includes badges)
|
|
234
|
+
PUT /api/posts/:id # Update post
|
|
235
|
+
DELETE /api/posts/:id # Delete post
|
|
236
|
+
GET /api/posts/:id/badges # Get post's badges
|
|
237
|
+
POST /api/posts/:id/badges?badge_id=X # Add badge to post
|
|
238
|
+
DELETE /api/posts/:post_id/badges/:badge_id # Remove badge from post
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Testing
|
|
242
|
+
|
|
243
|
+
Run tests with:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
cd test/dummy
|
|
247
|
+
bin/rails test
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Project Structure
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
lib/
|
|
254
|
+
├── rails_badgeable.rb # Main entry point
|
|
255
|
+
├── rails_badgeable/
|
|
256
|
+
│ ├── engine.rb # Engine definition
|
|
257
|
+
│ └── version.rb # Version info
|
|
258
|
+
app/models/
|
|
259
|
+
├── rails_badgeable/
|
|
260
|
+
│ ├── badge.rb # Badge model
|
|
261
|
+
│ └── badge_assignment.rb # Join model
|
|
262
|
+
└── models/concerns/
|
|
263
|
+
└── rails_badgeable/
|
|
264
|
+
└── has_badges.rb # Concern for host models
|
|
265
|
+
db/migrate/
|
|
266
|
+
└── xxx_create_rails_badgeable_tables.rb # Migration generator
|
|
267
|
+
lib/generators/
|
|
268
|
+
└── rails_badgeable/
|
|
269
|
+
└── alias/ # Short alias generator
|
|
270
|
+
├── USAGE
|
|
271
|
+
├── alias_generator.rb
|
|
272
|
+
└── templates/
|
|
273
|
+
└── badgeable.rb
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Usage Notes for Agents
|
|
277
|
+
|
|
278
|
+
- **Always use full namespace** unless alias generator was run: `RailsBadgeable::Badge`
|
|
279
|
+
- **Badge names are unique** - `find_or_create_by(name: "Important")` is safe
|
|
280
|
+
- **Polymorphic type stores class name** - uses `base_class.name` for STI support
|
|
281
|
+
- **Database prevents duplicates** - unique index on `[badge_id, assignable_type, assignable_id]`
|
|
282
|
+
- **No automatic top-level constants** - users must run alias generator for `Badge` constant
|
|
283
|
+
- **Engine is not mountable** - no routes, controllers, or views included
|
|
284
|
+
- **Migrations must be copied** - use `rails rails_badgeable:install:migrations`
|
|
285
|
+
- **Custom fields require migration** - add columns directly to tables if needed
|
|
286
|
+
- **Join table accessible** - `model.rails_badgeable_assignments` for metadata access
|
|
287
|
+
|
|
288
|
+
## Development
|
|
289
|
+
|
|
290
|
+
- Rails Engine (non-mountable)
|
|
291
|
+
- Ruby 3.0+ required
|
|
292
|
+
- Rails 6.0+ compatible
|
|
293
|
+
- MIT License
|
|
294
|
+
- Author: aric.zheng <1290657123@qq.com>
|
metadata
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails_badgeable
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- aric.zheng
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-01-31 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '6.0'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '6.0'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9.0'
|
|
33
|
+
description: A lightweight Rails Engine that enables any ActiveRecord model to associate
|
|
34
|
+
with predefined badges via polymorphic many-to-many relationships. Features database-level
|
|
35
|
+
constraints, namespace isolation, and optional short aliases.
|
|
36
|
+
email:
|
|
37
|
+
- 1290657123@qq.com
|
|
38
|
+
executables: []
|
|
39
|
+
extensions: []
|
|
40
|
+
extra_rdoc_files: []
|
|
41
|
+
files:
|
|
42
|
+
- MIT-LICENSE
|
|
43
|
+
- README.md
|
|
44
|
+
- Rakefile
|
|
45
|
+
- app/models/concerns/rails_badgeable/has_badges.rb
|
|
46
|
+
- app/models/rails_badgeable/badge.rb
|
|
47
|
+
- app/models/rails_badgeable/badge_assignment.rb
|
|
48
|
+
- db/migrate/20250131000000_create_rails_badgeable_tables.rb
|
|
49
|
+
- lib/generators/rails_badgeable/alias/USAGE
|
|
50
|
+
- lib/generators/rails_badgeable/alias/alias_generator.rb
|
|
51
|
+
- lib/generators/rails_badgeable/alias/templates/badgeable.rb
|
|
52
|
+
- lib/rails_badgeable.rb
|
|
53
|
+
- lib/rails_badgeable/engine.rb
|
|
54
|
+
- lib/rails_badgeable/version.rb
|
|
55
|
+
- lib/tasks/rails_badgeable_tasks.rake
|
|
56
|
+
- llms.txt
|
|
57
|
+
homepage: https://github.com/afeiship/rails_badgeable
|
|
58
|
+
licenses:
|
|
59
|
+
- MIT
|
|
60
|
+
metadata:
|
|
61
|
+
homepage_uri: https://github.com/afeiship/rails_badgeable
|
|
62
|
+
changelog_uri: https://github.com/afeiship/rails_badgeable/blob/main/CHANGELOG.md
|
|
63
|
+
documentation_uri: https://github.com/afeiship/rails_badgeable/blob/main/README.md
|
|
64
|
+
ai_assistant_uri: https://github.com/afeiship/rails_badgeable/blob/main/llms.txt
|
|
65
|
+
post_install_message:
|
|
66
|
+
rdoc_options: []
|
|
67
|
+
require_paths:
|
|
68
|
+
- lib
|
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: 3.0.0
|
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: '0'
|
|
79
|
+
requirements: []
|
|
80
|
+
rubygems_version: 3.5.22
|
|
81
|
+
signing_key:
|
|
82
|
+
specification_version: 4
|
|
83
|
+
summary: A Rails engine for polymorphic, reusable badges on any model.
|
|
84
|
+
test_files: []
|