rails_ui_guard 0.1.0 → 0.1.2
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 +4 -4
- data/CHANGELOG.md +57 -0
- data/GEM_SETUP_COMPLETE.md +156 -0
- data/LICENSE.txt +22 -0
- data/PUSH_INSTRUCTIONS.md +34 -0
- data/PUSH_TO_GITHUB.md +90 -0
- data/README.md +243 -0
- data/lib/generators/rails_ui_guard/install/install_generator.rb +27 -0
- data/lib/generators/rails_ui_guard/install/templates/README +32 -0
- data/lib/generators/rails_ui_guard/install/templates/create_rails_ui_guard_feature_statuses.rb.erb +21 -0
- data/lib/generators/rails_ui_guard/install/templates/rails_ui_guard.rb +6 -0
- data/lib/rails_ui_guard/app/models/rails_ui_guard/feature_status.rb +47 -0
- data/lib/rails_ui_guard/app/views/rails_ui_guard/shared/_module_overlay.html.erb +99 -0
- data/lib/rails_ui_guard/concerns/feature_statusable.rb +72 -0
- data/lib/rails_ui_guard/controller_helpers.rb +78 -0
- data/lib/rails_ui_guard/engine.rb +45 -0
- data/lib/rails_ui_guard/version.rb +6 -0
- data/lib/rails_ui_guard/view_helpers.rb +71 -0
- data/lib/rails_ui_guard.rb +31 -0
- data/rails_ui_guard.gemspec +55 -0
- data/setup_gem.sh +33 -0
- metadata +23 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 61899138e5084d28920593b3060faaac214c2540971464404f1f604289edf1f8
|
|
4
|
+
data.tar.gz: d1f03018d264f07438fc58d43ff375def297f78e2c7b1029d664a2a8561f5c36
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d3f1a1955f6784f541071da0f1f854557b19592ea920112055921fd2c4e6f52663fac627415496a344455887a9035f87d79e70df20f786915fbe7326776dae6
|
|
7
|
+
data.tar.gz: f50595925a3d524a262d217c8035c99331f5b8448677915caa7deacaedfcdf595733607e3755e9a403e77dbe1a820dd04d27bcc80d9b6cf4c80a4bda01b110fb
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.2] - 2024-12-28
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Fixed ApplicationRecord loading issue - FeatureStatus model now loads after ApplicationRecord is available
|
|
12
|
+
- Removed early require of FeatureStatus model from main gem file
|
|
13
|
+
- Model now loads via engine's config.to_prepare block
|
|
14
|
+
|
|
15
|
+
## [0.1.1] - 2024-12-28
|
|
16
|
+
|
|
17
|
+
### Enhanced
|
|
18
|
+
- Improved overlay UI with better visual design
|
|
19
|
+
- Enhanced color-coded headers (red for locked, yellow for under work)
|
|
20
|
+
- Better icon display with rounded backgrounds
|
|
21
|
+
- Improved message formatting and readability
|
|
22
|
+
- Added action buttons (Go to Dashboard, Manage Access for admins)
|
|
23
|
+
- Enhanced CSS with animations (fade-in, slide-up)
|
|
24
|
+
- Better backdrop blur effects
|
|
25
|
+
- More user-friendly default messages
|
|
26
|
+
- Improved mobile responsiveness
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- Better handling of feature status records
|
|
30
|
+
- Improved variable scope in overlay partial
|
|
31
|
+
|
|
32
|
+
## [0.1.0] - 2024-12-28
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- Initial release of Rails UI Guard
|
|
36
|
+
- Feature status management (Active, Locked, Under Work)
|
|
37
|
+
- UI blur/overlay system (no JavaScript required)
|
|
38
|
+
- Backend enforcement helpers
|
|
39
|
+
- Sidebar status badges with icons
|
|
40
|
+
- View helpers for rendering overlays
|
|
41
|
+
- Controller helpers for enforcing access
|
|
42
|
+
- Model concern for feature status management
|
|
43
|
+
- Rails Engine integration
|
|
44
|
+
- Migration generator
|
|
45
|
+
- Active Admin integration support
|
|
46
|
+
- Comprehensive documentation
|
|
47
|
+
|
|
48
|
+
### Features
|
|
49
|
+
- Per-tenant feature locking
|
|
50
|
+
- Maintenance mode support
|
|
51
|
+
- Mobile-safe and accessible UI
|
|
52
|
+
- Rails 6/7/8 compatible
|
|
53
|
+
- Polymorphic statusable support
|
|
54
|
+
|
|
55
|
+
[0.1.1]: https://github.com/KapilDevPal/Rails-Ui-Guard/releases/tag/v0.1.1
|
|
56
|
+
[0.1.0]: https://github.com/KapilDevPal/Rails-Ui-Guard/releases/tag/v0.1.0
|
|
57
|
+
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# ✅ Rails UI Guard Gem - Setup Complete!
|
|
2
|
+
|
|
3
|
+
Your gem is ready to be pushed to GitHub and published to RubyGems.
|
|
4
|
+
|
|
5
|
+
## 📁 Gem Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
rails_ui_guard_gem/
|
|
9
|
+
├── lib/
|
|
10
|
+
│ ├── rails_ui_guard.rb # Main entry point
|
|
11
|
+
│ └── rails_ui_guard/
|
|
12
|
+
│ ├── version.rb # Version number
|
|
13
|
+
│ ├── engine.rb # Rails Engine
|
|
14
|
+
│ ├── controller_helpers.rb # Controller helpers
|
|
15
|
+
│ ├── view_helpers.rb # View helpers
|
|
16
|
+
│ ├── concerns/
|
|
17
|
+
│ │ └── feature_statusable.rb # Model concern
|
|
18
|
+
│ ├── app/
|
|
19
|
+
│ │ ├── models/
|
|
20
|
+
│ │ │ └── rails_ui_guard/
|
|
21
|
+
│ │ │ └── feature_status.rb # FeatureStatus model
|
|
22
|
+
│ │ └── views/
|
|
23
|
+
│ │ └── rails_ui_guard/
|
|
24
|
+
│ │ └── shared/
|
|
25
|
+
│ │ └── _module_overlay.html.erb
|
|
26
|
+
│ └── generators/
|
|
27
|
+
│ └── rails_ui_guard/
|
|
28
|
+
│ └── install/ # Install generator
|
|
29
|
+
├── rails_ui_guard.gemspec # Gem specification
|
|
30
|
+
├── README.md # Documentation
|
|
31
|
+
├── CHANGELOG.md # Version history
|
|
32
|
+
├── LICENSE.txt # MIT License
|
|
33
|
+
├── Gemfile # Development dependencies
|
|
34
|
+
├── Rakefile # Rake tasks
|
|
35
|
+
├── .gitignore # Git ignore rules
|
|
36
|
+
└── setup_gem.sh # Setup script
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 🚀 Quick Start - Push to GitHub
|
|
40
|
+
|
|
41
|
+
### Option 1: Use the setup script
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd rails_ui_guard_gem
|
|
45
|
+
./setup_gem.sh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then follow the printed instructions.
|
|
49
|
+
|
|
50
|
+
### Option 2: Manual steps
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cd rails_ui_guard_gem
|
|
54
|
+
|
|
55
|
+
# Initialize git (if not done)
|
|
56
|
+
git init
|
|
57
|
+
git branch -M main
|
|
58
|
+
|
|
59
|
+
# Add all files
|
|
60
|
+
git add .
|
|
61
|
+
|
|
62
|
+
# Commit
|
|
63
|
+
git commit -m "Initial commit: Rails UI Guard v0.1.0"
|
|
64
|
+
|
|
65
|
+
# Add remote
|
|
66
|
+
git remote add origin https://github.com/KapilDevPal/Rails-Ui-Guard.git
|
|
67
|
+
|
|
68
|
+
# Push
|
|
69
|
+
git push -u origin main
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 📦 Build and Test Gem
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Build the gem
|
|
76
|
+
gem build rails_ui_guard.gemspec
|
|
77
|
+
|
|
78
|
+
# Install locally to test
|
|
79
|
+
gem install rails_ui_guard-0.1.0.gem --local
|
|
80
|
+
|
|
81
|
+
# Test in a Rails app
|
|
82
|
+
cd /path/to/test/app
|
|
83
|
+
# Add to Gemfile: gem 'rails_ui_guard', path: '/path/to/rails_ui_guard_gem'
|
|
84
|
+
bundle install
|
|
85
|
+
rails generate rails_ui_guard:install
|
|
86
|
+
rails db:migrate
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 📤 Publish to RubyGems
|
|
90
|
+
|
|
91
|
+
1. **Sign up** at https://rubygems.org
|
|
92
|
+
2. **Get your API key** from https://rubygems.org/profile/edit
|
|
93
|
+
3. **Push the gem**:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
gem push rails_ui_guard-0.1.0.gem
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 📝 Using the Gem
|
|
100
|
+
|
|
101
|
+
### From GitHub
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
# Gemfile
|
|
105
|
+
gem 'rails_ui_guard', git: 'https://github.com/KapilDevPal/Rails-Ui-Guard.git'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### From RubyGems (after publishing)
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# Gemfile
|
|
112
|
+
gem 'rails_ui_guard'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Installation
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
bundle install
|
|
119
|
+
rails generate rails_ui_guard:install
|
|
120
|
+
rails db:migrate
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## ✨ Features Included
|
|
124
|
+
|
|
125
|
+
- ✅ Complete gem structure
|
|
126
|
+
- ✅ Rails Engine integration
|
|
127
|
+
- ✅ Migration generator
|
|
128
|
+
- ✅ Model concern for feature status
|
|
129
|
+
- ✅ Controller helpers
|
|
130
|
+
- ✅ View helpers
|
|
131
|
+
- ✅ UI overlay partial
|
|
132
|
+
- ✅ Status badges
|
|
133
|
+
- ✅ Comprehensive README
|
|
134
|
+
- ✅ MIT License
|
|
135
|
+
- ✅ CHANGELOG
|
|
136
|
+
- ✅ GitHub Actions CI (optional)
|
|
137
|
+
|
|
138
|
+
## 📚 Documentation
|
|
139
|
+
|
|
140
|
+
- **README.md** - Complete usage guide
|
|
141
|
+
- **PUSH_TO_GITHUB.md** - Step-by-step GitHub push instructions
|
|
142
|
+
- **CHANGELOG.md** - Version history
|
|
143
|
+
|
|
144
|
+
## 🎉 Next Steps
|
|
145
|
+
|
|
146
|
+
1. ✅ Review the gem structure
|
|
147
|
+
2. ✅ Test building the gem
|
|
148
|
+
3. ✅ Push to GitHub
|
|
149
|
+
4. ✅ Test in a sample Rails app
|
|
150
|
+
5. ✅ Publish to RubyGems (optional)
|
|
151
|
+
6. ✅ Share with the community!
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
**Happy coding! 🚀**
|
|
156
|
+
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Kapil Dev Pal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Push Instructions for Rails UI Guard v0.1.1
|
|
2
|
+
|
|
3
|
+
## Changes Made
|
|
4
|
+
- Enhanced overlay UI with better visual design
|
|
5
|
+
- Improved color-coded headers (red for locked, yellow for under work)
|
|
6
|
+
- Better icon display with rounded backgrounds
|
|
7
|
+
- Added action buttons (Go to Dashboard, Manage Access)
|
|
8
|
+
- Enhanced CSS animations and blur effects
|
|
9
|
+
- Better mobile responsiveness
|
|
10
|
+
|
|
11
|
+
## To Push to GitHub:
|
|
12
|
+
```bash
|
|
13
|
+
cd /tmp/rails_ui_guard_update
|
|
14
|
+
git push origin main
|
|
15
|
+
git push origin v0.1.1
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## To Push to RubyGems:
|
|
19
|
+
```bash
|
|
20
|
+
cd /tmp/rails_ui_guard_update
|
|
21
|
+
gem push rails_ui_guard-0.1.1.gem
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
You will need:
|
|
25
|
+
- GitHub credentials (username/password or token)
|
|
26
|
+
- RubyGems credentials (API key from https://rubygems.org/settings/edit)
|
|
27
|
+
|
|
28
|
+
## Files Updated:
|
|
29
|
+
- lib/rails_ui_guard/app/views/rails_ui_guard/shared/_module_overlay.html.erb
|
|
30
|
+
- lib/rails_ui_guard/version.rb (0.1.0 -> 0.1.1)
|
|
31
|
+
- CHANGELOG.md
|
|
32
|
+
|
|
33
|
+
## Gem File Location:
|
|
34
|
+
/tmp/rails_ui_guard_update/rails_ui_guard-0.1.1.gem
|
data/PUSH_TO_GITHUB.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# How to Push Rails UI Guard to GitHub
|
|
2
|
+
|
|
3
|
+
## Step 1: Navigate to the gem directory
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd rails_ui_guard_gem
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Step 2: Initialize Git (if not already done)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git init
|
|
13
|
+
git branch -M main
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Step 3: Add all files
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git add .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Step 4: Make initial commit
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git commit -m "Initial commit: Rails UI Guard v0.1.0 - Feature locking and status management system for Rails"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Step 5: Add GitHub remote
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git remote add origin https://github.com/KapilDevPal/Rails-Ui-Guard.git
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Step 6: Push to GitHub
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git push -u origin main
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Step 7: Build and test the gem locally
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
gem build rails_ui_guard.gemspec
|
|
44
|
+
gem install rails_ui_guard-0.1.0.gem --local
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Step 8: Publish to RubyGems (optional)
|
|
48
|
+
|
|
49
|
+
First, sign up at https://rubygems.org and get your API key.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
gem push rails_ui_guard-0.1.0.gem
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Setup Script
|
|
56
|
+
|
|
57
|
+
You can also use the provided setup script:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
./setup_gem.sh
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then follow the instructions it prints.
|
|
64
|
+
|
|
65
|
+
## Using the Gem
|
|
66
|
+
|
|
67
|
+
### From GitHub
|
|
68
|
+
|
|
69
|
+
Add to your Gemfile:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
gem 'rails_ui_guard', git: 'https://github.com/KapilDevPal/Rails-Ui-Guard.git'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### From RubyGems (after publishing)
|
|
76
|
+
|
|
77
|
+
Add to your Gemfile:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
gem 'rails_ui_guard'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
bundle install
|
|
87
|
+
rails generate rails_ui_guard:install
|
|
88
|
+
rails db:migrate
|
|
89
|
+
```
|
|
90
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Rails UI Guard
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/rails_ui_guard)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Feature locking and status management system for Rails multi-tenant applications.
|
|
7
|
+
|
|
8
|
+
Rails UI Guard provides a clean way to lock/unlock features, show maintenance overlays, and enforce backend security for modules in multi-tenant Rails applications.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- ✅ **Per-tenant feature status management** (Active, Locked, Under Work)
|
|
13
|
+
- ✅ **UI blur/overlay system** (no JavaScript required)
|
|
14
|
+
- ✅ **Backend enforcement** for security
|
|
15
|
+
- ✅ **Sidebar status badges** with icons
|
|
16
|
+
- ✅ **Reusable view helpers and partials**
|
|
17
|
+
- ✅ **Rails 6/7/8 compatible**
|
|
18
|
+
- ✅ **Mobile-safe and accessible**
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Add this line to your application's Gemfile:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
gem 'rails_ui_guard', git: 'https://github.com/KapilDevPal/Rails-Ui-Guard.git'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or if published to RubyGems:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
gem 'rails_ui_guard'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then execute:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
$ bundle install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Run the generator to create the migration and initializer:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
$ rails generate rails_ui_guard:install
|
|
44
|
+
$ rails db:migrate
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
### 1. Include in your model (e.g., School)
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
class School < ApplicationRecord
|
|
53
|
+
include RailsUiGuard::FeatureStatusable
|
|
54
|
+
has_feature_status
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Include in ApplicationController
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
class ApplicationController < ActionController::Base
|
|
62
|
+
include RailsUiGuard::ControllerHelpers
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Use in your controllers
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
class FeesController < ApplicationController
|
|
70
|
+
before_action :set_current_school
|
|
71
|
+
before_action -> { enforce_feature_access("fee_management") }
|
|
72
|
+
|
|
73
|
+
def index
|
|
74
|
+
@module_status = current_school.module_status("fee_management")
|
|
75
|
+
# ... rest of action
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 4. Add to your layout
|
|
81
|
+
|
|
82
|
+
```erb
|
|
83
|
+
<!-- app/views/layouts/application.html.erb -->
|
|
84
|
+
<%= render_module_overlay(@module_status) %>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 5. Add status badges to sidebar (optional)
|
|
88
|
+
|
|
89
|
+
```erb
|
|
90
|
+
<!-- app/views/shared/_sidebar.html.erb -->
|
|
91
|
+
<% feature_key = app_module.name.parameterize(separator: '_') %>
|
|
92
|
+
<% module_status = current_school.module_status(feature_key) %>
|
|
93
|
+
<%= rails_ui_guard_status_badge(module_status) %>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Feature States
|
|
97
|
+
|
|
98
|
+
### Active (`:active`)
|
|
99
|
+
- Module is fully accessible and functional
|
|
100
|
+
- No restrictions or overlays
|
|
101
|
+
|
|
102
|
+
### Locked (`:locked`)
|
|
103
|
+
- Module is not enabled for this tenant
|
|
104
|
+
- Page content is blurred with lock overlay
|
|
105
|
+
- All interactions blocked
|
|
106
|
+
- Backend actions are blocked
|
|
107
|
+
|
|
108
|
+
### Under Work (`:under_work`)
|
|
109
|
+
- Module is temporarily unavailable (maintenance)
|
|
110
|
+
- Page content is blurred with maintenance overlay
|
|
111
|
+
- All interactions blocked
|
|
112
|
+
- Backend actions are blocked
|
|
113
|
+
|
|
114
|
+
## Usage Examples
|
|
115
|
+
|
|
116
|
+
### Setting Feature Status
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
# In Rails console or admin panel
|
|
120
|
+
school = School.find_by(name: "Demo School")
|
|
121
|
+
|
|
122
|
+
# Lock a feature
|
|
123
|
+
school.set_feature_status("fee_management", :locked,
|
|
124
|
+
message: "Fee Management is not available in your plan.",
|
|
125
|
+
help_text: "Contact sales@example.com to upgrade.")
|
|
126
|
+
|
|
127
|
+
# Set to under work
|
|
128
|
+
school.set_feature_status("fee_management", :under_work,
|
|
129
|
+
message: "Fee Management is under maintenance. Expected completion: 2:00 PM.")
|
|
130
|
+
|
|
131
|
+
# Set to active
|
|
132
|
+
school.set_feature_status("fee_management", :active)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Checking Feature Status
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
school.module_status("fee_management") # => :active, :locked, or :under_work
|
|
139
|
+
school.feature_active?("fee_management") # => true/false
|
|
140
|
+
school.feature_locked?("fee_management") # => true/false
|
|
141
|
+
school.feature_under_work?("fee_management") # => true/false
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Controller Helpers
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
# Set feature status (for overlay display)
|
|
148
|
+
rails_ui_guard_set_feature!("fee_management")
|
|
149
|
+
|
|
150
|
+
# Enforce active status (blocks non-active)
|
|
151
|
+
rails_ui_guard_enforce_active!("fee_management")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### View Helpers
|
|
155
|
+
|
|
156
|
+
```erb
|
|
157
|
+
<!-- Status badge -->
|
|
158
|
+
<%= rails_ui_guard_status_badge(module_status) %>
|
|
159
|
+
|
|
160
|
+
<!-- Wrap content with blur/overlay -->
|
|
161
|
+
<%= rails_ui_guard_wrap(status: @module_status, feature_key: "fee_management") do %>
|
|
162
|
+
<!-- Content here -->
|
|
163
|
+
<% end %>
|
|
164
|
+
|
|
165
|
+
<!-- Render overlay -->
|
|
166
|
+
<%= render_module_overlay(@module_status) %>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Active Admin Integration
|
|
170
|
+
|
|
171
|
+
The gem includes an Active Admin resource for managing feature statuses. To use it, create:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
# app/admin/feature_statuses.rb
|
|
175
|
+
ActiveAdmin.register RailsUiGuard::FeatureStatus, as: "FeatureStatus" do
|
|
176
|
+
menu label: "Module Lock & Status", priority: 5
|
|
177
|
+
|
|
178
|
+
permit_params :statusable_type, :statusable_id, :feature_key, :status, :message, :help_text
|
|
179
|
+
|
|
180
|
+
# ... rest of configuration
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
See the [full documentation](https://github.com/KapilDevPal/Rails-Ui-Guard) for complete Active Admin setup.
|
|
185
|
+
|
|
186
|
+
## Security
|
|
187
|
+
|
|
188
|
+
⚠️ **Important**: The UI blur/overlay is **UX only**. Backend enforcement is **mandatory** and cannot be bypassed by disabling JavaScript or manipulating the DOM.
|
|
189
|
+
|
|
190
|
+
Always use `enforce_feature_access` in your controllers:
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
before_action -> { enforce_feature_access("fee_management") }
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Requirements
|
|
197
|
+
|
|
198
|
+
- Ruby >= 2.7.0
|
|
199
|
+
- Rails >= 6.0, < 9.0
|
|
200
|
+
- ActiveRecord >= 6.0, < 9.0
|
|
201
|
+
|
|
202
|
+
## Development
|
|
203
|
+
|
|
204
|
+
After checking out the repo, run:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
$ bundle install
|
|
208
|
+
$ rake test
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
To build and install the gem:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
$ gem build rails_ui_guard.gemspec
|
|
215
|
+
$ gem install rails_ui_guard-0.1.0.gem
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Contributing
|
|
219
|
+
|
|
220
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/KapilDevPal/Rails-Ui-Guard.
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
225
|
+
|
|
226
|
+
## Author
|
|
227
|
+
|
|
228
|
+
**Kapil Dev Pal**
|
|
229
|
+
|
|
230
|
+
- GitHub: [@KapilDevPal](https://github.com/KapilDevPal)
|
|
231
|
+
- Email: kapildevpal@gmail.com
|
|
232
|
+
|
|
233
|
+
## Support
|
|
234
|
+
|
|
235
|
+
For questions or issues:
|
|
236
|
+
1. Check the [documentation](https://github.com/KapilDevPal/Rails-Ui-Guard)
|
|
237
|
+
2. Open an [issue](https://github.com/KapilDevPal/Rails-Ui-Guard/issues)
|
|
238
|
+
3. Contact the maintainer
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
Made with ❤️ for the Rails community
|
|
243
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsUiGuard
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Creates Rails UI Guard migration and initializer"
|
|
9
|
+
|
|
10
|
+
def create_migration
|
|
11
|
+
migration_template(
|
|
12
|
+
"create_rails_ui_guard_feature_statuses.rb.erb",
|
|
13
|
+
"db/migrate/create_rails_ui_guard_feature_statuses.rb"
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create_initializer
|
|
18
|
+
copy_file "rails_ui_guard.rb", "config/initializers/rails_ui_guard.rb"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def show_readme
|
|
22
|
+
readme "README" if behavior == :invoke
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Rails UI Guard has been installed!
|
|
2
|
+
|
|
3
|
+
Next steps:
|
|
4
|
+
|
|
5
|
+
1. Run the migration:
|
|
6
|
+
rails db:migrate
|
|
7
|
+
|
|
8
|
+
2. Include in your model (e.g., School):
|
|
9
|
+
class School < ApplicationRecord
|
|
10
|
+
include RailsUiGuard::FeatureStatusable
|
|
11
|
+
has_feature_status
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
3. Include in ApplicationController:
|
|
15
|
+
class ApplicationController < ActionController::Base
|
|
16
|
+
include RailsUiGuard::ControllerHelpers
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
4. Use in your controllers:
|
|
20
|
+
class FeesController < ApplicationController
|
|
21
|
+
before_action -> { enforce_feature_access("fee_management") }
|
|
22
|
+
|
|
23
|
+
def index
|
|
24
|
+
@module_status = current_school.module_status("fee_management")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
5. Add to your layout (app/views/layouts/application.html.erb):
|
|
29
|
+
<%= render_module_overlay(@module_status) %>
|
|
30
|
+
|
|
31
|
+
For complete documentation, see: https://github.com/KapilDevPal/Rails-Ui-Guard
|
|
32
|
+
|
data/lib/generators/rails_ui_guard/install/templates/create_rails_ui_guard_feature_statuses.rb.erb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class CreateRailsUiGuardFeatureStatuses < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :rails_ui_guard_feature_statuses, id: :uuid do |t|
|
|
4
|
+
t.references :statusable, polymorphic: true, null: false, type: :uuid, index: true
|
|
5
|
+
t.string :feature_key, null: false
|
|
6
|
+
t.string :status, null: false, default: "active"
|
|
7
|
+
t.text :message
|
|
8
|
+
t.text :help_text
|
|
9
|
+
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_index :rails_ui_guard_feature_statuses,
|
|
14
|
+
[:statusable_type, :statusable_id, :feature_key],
|
|
15
|
+
unique: true,
|
|
16
|
+
name: "index_rails_ui_guard_feature_statuses_unique"
|
|
17
|
+
add_index :rails_ui_guard_feature_statuses, :feature_key
|
|
18
|
+
add_index :rails_ui_guard_feature_statuses, :status
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsUiGuard
|
|
4
|
+
# DB-backed feature status record.
|
|
5
|
+
#
|
|
6
|
+
# This is the source of truth for per-tenant module/sub-module availability.
|
|
7
|
+
#
|
|
8
|
+
# - statusable: typically School (multi-tenant), but polymorphic for extensibility.
|
|
9
|
+
# - feature_key: stable string key for the module/submodule (e.g. "Fee Management" or "fees_module")
|
|
10
|
+
# - status: :active | :locked | :under_work (extensible)
|
|
11
|
+
class FeatureStatus < ::ApplicationRecord
|
|
12
|
+
self.table_name = "rails_ui_guard_feature_statuses"
|
|
13
|
+
|
|
14
|
+
belongs_to :statusable, polymorphic: true
|
|
15
|
+
|
|
16
|
+
validates :feature_key, presence: true
|
|
17
|
+
validates :status, presence: true
|
|
18
|
+
validates :feature_key, uniqueness: { scope: %i[statusable_type statusable_id] }
|
|
19
|
+
|
|
20
|
+
# Keep statuses as strings for easy future expansion without migrations.
|
|
21
|
+
STATUSES = %w[active locked under_work].freeze
|
|
22
|
+
|
|
23
|
+
validates :status, inclusion: { in: STATUSES }
|
|
24
|
+
|
|
25
|
+
def active?
|
|
26
|
+
status == "active"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def locked?
|
|
30
|
+
status == "locked"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def under_work?
|
|
34
|
+
status == "under_work"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.ransackable_attributes(_auth_object = nil)
|
|
38
|
+
%w[id statusable_type statusable_id feature_key status message help_text created_at updated_at]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.ransackable_associations(_auth_object = nil)
|
|
42
|
+
%w[statusable]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<%# Enhanced user-friendly overlay with lock details %>
|
|
2
|
+
<%# This provides a transparent overlay with clear messaging when modules are locked or under maintenance %>
|
|
3
|
+
|
|
4
|
+
<%
|
|
5
|
+
status = module_status&.to_sym || :active
|
|
6
|
+
feature_key = feature_key&.to_s
|
|
7
|
+
|
|
8
|
+
# Determine icon, title, and colors based on status
|
|
9
|
+
case status
|
|
10
|
+
when :locked
|
|
11
|
+
icon = "🔒"
|
|
12
|
+
title = "Module Locked"
|
|
13
|
+
bg_color = "bg-red-500"
|
|
14
|
+
text_color = "text-red-700"
|
|
15
|
+
border_color = "border-red-300"
|
|
16
|
+
icon_bg = "bg-red-100"
|
|
17
|
+
when :under_work
|
|
18
|
+
icon = "🚧"
|
|
19
|
+
title = "Under Maintenance"
|
|
20
|
+
bg_color = "bg-yellow-500"
|
|
21
|
+
text_color = "text-yellow-700"
|
|
22
|
+
border_color = "border-yellow-300"
|
|
23
|
+
icon_bg = "bg-yellow-100"
|
|
24
|
+
else
|
|
25
|
+
# Should not render if active, but just in case
|
|
26
|
+
return
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get custom message or use default
|
|
30
|
+
message = feature_status&.message.presence
|
|
31
|
+
if message.blank?
|
|
32
|
+
case status
|
|
33
|
+
when :locked
|
|
34
|
+
message = "This module is currently locked and not available for your school. Please contact your administrator for more information."
|
|
35
|
+
when :under_work
|
|
36
|
+
message = "This module is currently under maintenance. We're working hard to bring it back online soon. Please check back later."
|
|
37
|
+
else
|
|
38
|
+
message = "This module is currently unavailable."
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
help_text = feature_status&.help_text
|
|
42
|
+
%>
|
|
43
|
+
|
|
44
|
+
<div class="rails-ui-guard-overlay fixed inset-0 flex items-center justify-center z-[10000] pointer-events-auto"
|
|
45
|
+
style="background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);">
|
|
46
|
+
<div class="rails-ui-guard-overlay-content bg-white rounded-2xl shadow-2xl max-w-md w-full mx-4 transform transition-all duration-300 scale-100 <%= border_color %> border-2">
|
|
47
|
+
<!-- Header with Icon -->
|
|
48
|
+
<div class="<%= bg_color %> rounded-t-xl px-6 py-4 flex items-center space-x-4">
|
|
49
|
+
<div class="<%= icon_bg %> rounded-full p-3 flex items-center justify-center">
|
|
50
|
+
<span class="text-3xl"><%= icon %></span>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="flex-1">
|
|
53
|
+
<h2 class="text-xl font-bold text-white"><%= title %></h2>
|
|
54
|
+
<% if feature_key.present? %>
|
|
55
|
+
<p class="text-sm text-white opacity-90 mt-1">
|
|
56
|
+
<%= feature_key.humanize %>
|
|
57
|
+
</p>
|
|
58
|
+
<% end %>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<!-- Content -->
|
|
63
|
+
<div class="px-6 py-6">
|
|
64
|
+
<div class="<%= text_color %> mb-4">
|
|
65
|
+
<p class="text-base leading-relaxed whitespace-pre-wrap"><%= message %></p>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<% if help_text.present? %>
|
|
69
|
+
<div class="mt-4 pt-4 border-t border-gray-200">
|
|
70
|
+
<p class="text-sm text-gray-600 leading-relaxed whitespace-pre-wrap">
|
|
71
|
+
<strong class="text-gray-800">Need Help?</strong><br>
|
|
72
|
+
<%= help_text %>
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
<% end %>
|
|
76
|
+
|
|
77
|
+
<!-- Action Buttons -->
|
|
78
|
+
<div class="mt-6 flex flex-col sm:flex-row gap-3">
|
|
79
|
+
<% if defined?(root_path) %>
|
|
80
|
+
<%= link_to root_path,
|
|
81
|
+
class: "flex-1 px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg font-medium text-center transition-colors duration-200" do %>
|
|
82
|
+
<i class="fas fa-home mr-2"></i>
|
|
83
|
+
Go to Dashboard
|
|
84
|
+
<% end %>
|
|
85
|
+
<% end %>
|
|
86
|
+
|
|
87
|
+
<% if defined?(current_user) && (current_user&.respond_to?(:super_admin?) && current_user&.super_admin?) || (current_user&.respond_to?(:school_head?) && current_user&.school_head?) %>
|
|
88
|
+
<% if defined?(admin_feature_statuses_path) %>
|
|
89
|
+
<%= link_to admin_feature_statuses_path,
|
|
90
|
+
class: "flex-1 px-4 py-2 #{bg_color} hover:opacity-90 text-white rounded-lg font-medium text-center transition-opacity duration-200" do %>
|
|
91
|
+
<i class="fas fa-cog mr-2"></i>
|
|
92
|
+
Manage Access
|
|
93
|
+
<% end %>
|
|
94
|
+
<% end %>
|
|
95
|
+
<% end %>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Concern to add feature status methods to models (e.g., School)
|
|
4
|
+
# Provides module_status(feature_key) method that returns :active, :locked, or :under_work
|
|
5
|
+
module RailsUiGuard::FeatureStatusable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
# Returns the FeatureStatus record (if present) for a given feature_key.
|
|
9
|
+
# Useful for retrieving message/help_text in the UI overlay.
|
|
10
|
+
def feature_status_record(feature_key)
|
|
11
|
+
feature_key = feature_key.to_s
|
|
12
|
+
feature_statuses.find_by(feature_key: feature_key)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns the status of a feature/module for this record
|
|
16
|
+
# @param feature_key [String, Symbol] The key identifying the feature/module
|
|
17
|
+
# @return [Symbol] :active, :locked, or :under_work
|
|
18
|
+
def module_status(feature_key)
|
|
19
|
+
feature_key = feature_key.to_s
|
|
20
|
+
|
|
21
|
+
# Check if there's a feature_status record for this feature
|
|
22
|
+
status_record = feature_status_record(feature_key)
|
|
23
|
+
return status_record.status.to_sym if status_record
|
|
24
|
+
|
|
25
|
+
# Fallback: Check module_access if it exists (backward compatibility)
|
|
26
|
+
if respond_to?(:module_accesses)
|
|
27
|
+
module_access = module_accesses.joins(:app_module).find_by(app_modules: { name: feature_key })
|
|
28
|
+
if module_access
|
|
29
|
+
return module_access.granted? ? :active : :locked
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Default to active if no status is set
|
|
34
|
+
:active
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Check if a feature is active
|
|
38
|
+
def feature_active?(feature_key)
|
|
39
|
+
module_status(feature_key) == :active
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Check if a feature is locked
|
|
43
|
+
def feature_locked?(feature_key)
|
|
44
|
+
module_status(feature_key) == :locked
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Check if a feature is under work
|
|
48
|
+
def feature_under_work?(feature_key)
|
|
49
|
+
module_status(feature_key) == :under_work
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Set the status of a feature
|
|
53
|
+
def set_feature_status(feature_key, status, message: nil, help_text: nil)
|
|
54
|
+
status_record = feature_statuses.find_or_initialize_by(feature_key: feature_key.to_s)
|
|
55
|
+
status_record.status = status.to_s
|
|
56
|
+
status_record.message = message if message.present?
|
|
57
|
+
status_record.help_text = help_text if help_text.present?
|
|
58
|
+
status_record.save!
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class_methods do
|
|
62
|
+
# Include this in your model to add feature status support
|
|
63
|
+
# Requires has_many :feature_statuses association
|
|
64
|
+
def has_feature_status
|
|
65
|
+
has_many :feature_statuses,
|
|
66
|
+
class_name: 'RailsUiGuard::FeatureStatus',
|
|
67
|
+
dependent: :destroy,
|
|
68
|
+
as: :statusable
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsUiGuard
|
|
4
|
+
# Controller helpers for enforcing feature/module access (backend security)
|
|
5
|
+
#
|
|
6
|
+
# Pattern:
|
|
7
|
+
# class FeesController < ApplicationController
|
|
8
|
+
# before_action -> { rails_ui_guard_set_feature!("Fee Management") }
|
|
9
|
+
# before_action -> { rails_ui_guard_enforce_active!("Fee Management") }, only: [:create, :update, :destroy]
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# Notes:
|
|
13
|
+
# - Read actions can render normally (UX overlay will blur/freeze if locked)
|
|
14
|
+
# - Write actions MUST be blocked server-side to prevent URL/API bypass
|
|
15
|
+
module ControllerHelpers
|
|
16
|
+
extend ActiveSupport::Concern
|
|
17
|
+
|
|
18
|
+
included do
|
|
19
|
+
helper_method :rails_ui_guard_current_school
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Override by defining `current_school` in ApplicationController (you already have this).
|
|
23
|
+
def rails_ui_guard_current_school
|
|
24
|
+
respond_to?(:current_school) ? current_school : nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Sets instance variables used by the layout overlay:
|
|
28
|
+
# - @feature_key
|
|
29
|
+
# - @module_status (:active | :locked | :under_work | ...)
|
|
30
|
+
# - @feature_status_record (optional, provides message/help_text)
|
|
31
|
+
def rails_ui_guard_set_feature!(feature_key)
|
|
32
|
+
@feature_key = feature_key.to_s
|
|
33
|
+
school = rails_ui_guard_current_school
|
|
34
|
+
|
|
35
|
+
if school&.respond_to?(:module_status)
|
|
36
|
+
@module_status = school.module_status(@feature_key)
|
|
37
|
+
if school.respond_to?(:feature_status_record)
|
|
38
|
+
@feature_status_record = school.feature_status_record(@feature_key)
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
@module_status = :active
|
|
42
|
+
@feature_status_record = nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Backend enforcement: blocks non-active access for critical actions.
|
|
47
|
+
#
|
|
48
|
+
# - For HTML: redirect back (or to root) with a clear flash
|
|
49
|
+
# - For JSON: returns 403
|
|
50
|
+
def rails_ui_guard_enforce_active!(feature_key, redirect_to: nil)
|
|
51
|
+
school = rails_ui_guard_current_school
|
|
52
|
+
status = school&.respond_to?(:module_status) ? school.module_status(feature_key) : :active
|
|
53
|
+
return if status.to_sym == :active
|
|
54
|
+
|
|
55
|
+
message =
|
|
56
|
+
case status.to_sym
|
|
57
|
+
when :locked
|
|
58
|
+
"This feature is not enabled for your school."
|
|
59
|
+
when :under_work
|
|
60
|
+
"This feature is temporarily unavailable (maintenance/under work)."
|
|
61
|
+
else
|
|
62
|
+
"This feature is currently unavailable."
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
respond_to do |format|
|
|
66
|
+
format.html do
|
|
67
|
+
flash[:alert] = message
|
|
68
|
+
target = redirect_to || (request.referer.presence || main_app.root_path)
|
|
69
|
+
redirect_to target
|
|
70
|
+
end
|
|
71
|
+
format.json { render json: { error: message, feature_status: status }, status: :forbidden }
|
|
72
|
+
format.any { head :forbidden }
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsUiGuard
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace RailsUiGuard
|
|
6
|
+
engine_name "rails_ui_guard"
|
|
7
|
+
|
|
8
|
+
# Configure paths for views, models, and assets
|
|
9
|
+
config.autoload_paths << root.join("app", "models")
|
|
10
|
+
|
|
11
|
+
paths["app/views"] = root.join("app", "views")
|
|
12
|
+
paths["app/models"] = root.join("app", "models")
|
|
13
|
+
paths["app/helpers"] = root.join("app", "helpers")
|
|
14
|
+
paths["app/assets"] = root.join("app", "assets")
|
|
15
|
+
|
|
16
|
+
# Load the FeatureStatus model after Rails is fully initialized
|
|
17
|
+
# This ensures ApplicationRecord is available
|
|
18
|
+
config.to_prepare do
|
|
19
|
+
require root.join("app", "models", "rails_ui_guard", "feature_status") unless defined?(RailsUiGuard::FeatureStatus)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Make view helpers available globally
|
|
23
|
+
initializer "rails_ui_guard.view_helpers" do
|
|
24
|
+
ActiveSupport.on_load(:action_view) do
|
|
25
|
+
include RailsUiGuard::ViewHelpers
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Make controller helpers available and register view helpers
|
|
30
|
+
initializer "rails_ui_guard.controller_helpers" do
|
|
31
|
+
ActiveSupport.on_load(:action_controller_base) do
|
|
32
|
+
include RailsUiGuard::ControllerHelpers
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Register helpers so they're available in all views
|
|
37
|
+
initializer "rails_ui_guard.register_helpers" do
|
|
38
|
+
ActiveSupport.on_load(:action_controller) do
|
|
39
|
+
helper RailsUiGuard::ViewHelpers
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsUiGuard
|
|
4
|
+
# View helpers for the blur + overlay UX.
|
|
5
|
+
#
|
|
6
|
+
# This is intentionally **no-JS**. The UI lock is UX only; backend enforcement
|
|
7
|
+
# must still be done with `rails_ui_guard_enforce_active!` for write actions.
|
|
8
|
+
module ViewHelpers
|
|
9
|
+
# Wrap arbitrary content with a blur/freeze overlay when status != :active.
|
|
10
|
+
#
|
|
11
|
+
# Usage (recommended in layout):
|
|
12
|
+
#
|
|
13
|
+
# <%= rails_ui_guard_wrap(status: @module_status, feature_key: @feature_key, feature_status: @feature_status_record) do %>
|
|
14
|
+
# <%= yield %>
|
|
15
|
+
# <% end %>
|
|
16
|
+
#
|
|
17
|
+
def rails_ui_guard_wrap(status:, feature_key: nil, feature_status: nil, &block)
|
|
18
|
+
status = status&.to_sym
|
|
19
|
+
content = capture(&block)
|
|
20
|
+
|
|
21
|
+
return content if status.nil? || status == :active
|
|
22
|
+
|
|
23
|
+
blurred_classes = "rails-ui-guard-blur rails-ui-guard-opacity rails-ui-guard-block-pointer"
|
|
24
|
+
# `inert` prevents focus/keyboard interaction in modern browsers (no JS needed).
|
|
25
|
+
inert_attr = "inert"
|
|
26
|
+
|
|
27
|
+
safe_join(
|
|
28
|
+
[
|
|
29
|
+
content_tag(:div, class: "relative") do
|
|
30
|
+
safe_join(
|
|
31
|
+
[
|
|
32
|
+
content_tag(:div, content, class: blurred_classes, **{ inert: inert_attr }),
|
|
33
|
+
render(
|
|
34
|
+
"rails_ui_guard/shared/module_overlay",
|
|
35
|
+
module_status: status,
|
|
36
|
+
feature_key: feature_key,
|
|
37
|
+
feature_status: feature_status
|
|
38
|
+
)
|
|
39
|
+
]
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
]
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Optional: show lock/maintenance badge for menu items.
|
|
47
|
+
def rails_ui_guard_status_badge(status)
|
|
48
|
+
status = status&.to_sym
|
|
49
|
+
return "" if status.nil? || status == :active
|
|
50
|
+
|
|
51
|
+
label, classes, icon =
|
|
52
|
+
case status
|
|
53
|
+
when :locked
|
|
54
|
+
["Locked", "bg-gray-700 text-gray-200", "🔒"]
|
|
55
|
+
when :under_work
|
|
56
|
+
["Under Work", "bg-yellow-700 text-yellow-100", "🚧"]
|
|
57
|
+
else
|
|
58
|
+
["Unavailable", "bg-red-700 text-red-100", "⚠️"]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
content_tag(:span, class: "ml-auto flex items-center gap-1 text-[10px] px-2 py-0.5 rounded #{classes}") do
|
|
62
|
+
safe_join([
|
|
63
|
+
content_tag(:span, icon, class: "text-xs"),
|
|
64
|
+
content_tag(:span, label)
|
|
65
|
+
])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rails_ui_guard
|
|
4
|
+
#
|
|
5
|
+
# Feature locking and status management system for Rails multi-tenant applications.
|
|
6
|
+
#
|
|
7
|
+
# This gem provides:
|
|
8
|
+
# - A DB-driven feature-status model (per-tenant)
|
|
9
|
+
# - Controller guards (backend enforcement)
|
|
10
|
+
# - View helpers + reusable overlay partial (UX blur/lock; no JS)
|
|
11
|
+
#
|
|
12
|
+
# See README.md for installation and usage instructions.
|
|
13
|
+
|
|
14
|
+
require "active_support"
|
|
15
|
+
|
|
16
|
+
# Ensure namespace exists even if files are loaded out-of-order.
|
|
17
|
+
module RailsUiGuard
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Core pieces (required early so models can safely `include RailsUiGuard::...`)
|
|
21
|
+
require_relative "rails_ui_guard/concerns/feature_statusable"
|
|
22
|
+
# Note: FeatureStatus model is loaded by the engine via config.to_prepare
|
|
23
|
+
# to ensure ApplicationRecord is available
|
|
24
|
+
|
|
25
|
+
require_relative "rails_ui_guard/version"
|
|
26
|
+
require_relative "rails_ui_guard/controller_helpers"
|
|
27
|
+
require_relative "rails_ui_guard/view_helpers"
|
|
28
|
+
|
|
29
|
+
# Engine hooks views/helpers into the host app and configures autoloading
|
|
30
|
+
require_relative "rails_ui_guard/engine" if defined?(Rails)
|
|
31
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/rails_ui_guard/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "rails_ui_guard"
|
|
7
|
+
spec.version = RailsUiGuard::VERSION
|
|
8
|
+
spec.authors = ["Kapil Dev Pal"]
|
|
9
|
+
spec.email = ["kapildevpal@gmail.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Feature locking and status management system for Rails multi-tenant applications"
|
|
12
|
+
spec.description = <<~DESC
|
|
13
|
+
Rails UI Guard provides a clean way to lock/unlock features, show maintenance overlays,
|
|
14
|
+
and enforce backend security for modules in multi-tenant Rails applications.
|
|
15
|
+
|
|
16
|
+
Features:
|
|
17
|
+
- Per-tenant feature status management (Active, Locked, Under Work)
|
|
18
|
+
- UI blur/overlay system (no JavaScript required)
|
|
19
|
+
- Backend enforcement for security
|
|
20
|
+
- Sidebar status badges
|
|
21
|
+
- Reusable view helpers and partials
|
|
22
|
+
- Rails 6/7/8 compatible
|
|
23
|
+
DESC
|
|
24
|
+
spec.homepage = "https://github.com/KapilDevPal/Rails-Ui-Guard"
|
|
25
|
+
spec.license = "MIT"
|
|
26
|
+
spec.required_ruby_version = ">= 2.7.0"
|
|
27
|
+
|
|
28
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
29
|
+
spec.metadata["source_code_uri"] = "#{spec.homepage}.git"
|
|
30
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
31
|
+
spec.metadata["rubygems_mfa_required"] = "false"
|
|
32
|
+
|
|
33
|
+
# Specify which files should be added to the gem when it is released.
|
|
34
|
+
spec.files = Dir.chdir(__dir__) do
|
|
35
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
36
|
+
(File.expand_path(f) == __FILE__) ||
|
|
37
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile Rakefile])
|
|
38
|
+
end
|
|
39
|
+
rescue
|
|
40
|
+
# If git is not available, include all files
|
|
41
|
+
Dir.glob("**/*", File::FNM_DOTMATCH).reject do |f|
|
|
42
|
+
File.directory?(f) ||
|
|
43
|
+
f.start_with?("bin/", "test/", "spec/", ".git", "Gemfile", "Rakefile") ||
|
|
44
|
+
f.end_with?(".gem")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
spec.bindir = "exe"
|
|
49
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
50
|
+
spec.require_paths = ["lib"]
|
|
51
|
+
|
|
52
|
+
spec.add_dependency "rails", ">= 6.0", "< 9.0"
|
|
53
|
+
spec.add_dependency "activerecord", ">= 6.0", "< 9.0"
|
|
54
|
+
end
|
|
55
|
+
|
data/setup_gem.sh
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Rails UI Guard Gem Setup Script
|
|
4
|
+
# This script helps set up the gem for GitHub and RubyGems
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
echo "🚀 Setting up Rails UI Guard gem..."
|
|
9
|
+
|
|
10
|
+
# Check if git is initialized
|
|
11
|
+
if [ ! -d ".git" ]; then
|
|
12
|
+
echo "📦 Initializing git repository..."
|
|
13
|
+
git init
|
|
14
|
+
git branch -M main
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Add all files
|
|
18
|
+
echo "📝 Adding files to git..."
|
|
19
|
+
git add .
|
|
20
|
+
|
|
21
|
+
# Build the gem
|
|
22
|
+
echo "🔨 Building gem..."
|
|
23
|
+
gem build rails_ui_guard.gemspec
|
|
24
|
+
|
|
25
|
+
echo "✅ Gem setup complete!"
|
|
26
|
+
echo ""
|
|
27
|
+
echo "Next steps:"
|
|
28
|
+
echo "1. Review the gem: gem install rails_ui_guard-*.gem --local"
|
|
29
|
+
echo "2. Add remote: git remote add origin https://github.com/KapilDevPal/Rails-Ui-Guard.git"
|
|
30
|
+
echo "3. Commit: git commit -m 'Initial commit: Rails UI Guard v0.1.0'"
|
|
31
|
+
echo "4. Push: git push -u origin main"
|
|
32
|
+
echo "5. Publish to RubyGems: gem push rails_ui_guard-*.gem"
|
|
33
|
+
|
metadata
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_ui_guard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kapil Dev Pal
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
10
|
date: 2025-12-28 00:00:00.000000000 Z
|
|
@@ -60,7 +59,27 @@ email:
|
|
|
60
59
|
executables: []
|
|
61
60
|
extensions: []
|
|
62
61
|
extra_rdoc_files: []
|
|
63
|
-
files:
|
|
62
|
+
files:
|
|
63
|
+
- CHANGELOG.md
|
|
64
|
+
- GEM_SETUP_COMPLETE.md
|
|
65
|
+
- LICENSE.txt
|
|
66
|
+
- PUSH_INSTRUCTIONS.md
|
|
67
|
+
- PUSH_TO_GITHUB.md
|
|
68
|
+
- README.md
|
|
69
|
+
- lib/generators/rails_ui_guard/install/install_generator.rb
|
|
70
|
+
- lib/generators/rails_ui_guard/install/templates/README
|
|
71
|
+
- lib/generators/rails_ui_guard/install/templates/create_rails_ui_guard_feature_statuses.rb.erb
|
|
72
|
+
- lib/generators/rails_ui_guard/install/templates/rails_ui_guard.rb
|
|
73
|
+
- lib/rails_ui_guard.rb
|
|
74
|
+
- lib/rails_ui_guard/app/models/rails_ui_guard/feature_status.rb
|
|
75
|
+
- lib/rails_ui_guard/app/views/rails_ui_guard/shared/_module_overlay.html.erb
|
|
76
|
+
- lib/rails_ui_guard/concerns/feature_statusable.rb
|
|
77
|
+
- lib/rails_ui_guard/controller_helpers.rb
|
|
78
|
+
- lib/rails_ui_guard/engine.rb
|
|
79
|
+
- lib/rails_ui_guard/version.rb
|
|
80
|
+
- lib/rails_ui_guard/view_helpers.rb
|
|
81
|
+
- rails_ui_guard.gemspec
|
|
82
|
+
- setup_gem.sh
|
|
64
83
|
homepage: https://github.com/KapilDevPal/Rails-Ui-Guard
|
|
65
84
|
licenses:
|
|
66
85
|
- MIT
|
|
@@ -69,7 +88,6 @@ metadata:
|
|
|
69
88
|
source_code_uri: https://github.com/KapilDevPal/Rails-Ui-Guard.git
|
|
70
89
|
changelog_uri: https://github.com/KapilDevPal/Rails-Ui-Guard/blob/main/CHANGELOG.md
|
|
71
90
|
rubygems_mfa_required: 'false'
|
|
72
|
-
post_install_message:
|
|
73
91
|
rdoc_options: []
|
|
74
92
|
require_paths:
|
|
75
93
|
- lib
|
|
@@ -84,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
102
|
- !ruby/object:Gem::Version
|
|
85
103
|
version: '0'
|
|
86
104
|
requirements: []
|
|
87
|
-
rubygems_version: 3.
|
|
88
|
-
signing_key:
|
|
105
|
+
rubygems_version: 3.6.3
|
|
89
106
|
specification_version: 4
|
|
90
107
|
summary: Feature locking and status management system for Rails multi-tenant applications
|
|
91
108
|
test_files: []
|