recycle_bin 1.0.0 → 1.1.1
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 +55 -2
- data/Gemfile +3 -3
- data/README.md +95 -9
- data/app/controllers/recycle_bin/trash_controller.rb +120 -24
- data/app/views/{layouts/recycle_bin/application.html.erb → recycle_bin/layouts/recycle_bin.html.erb} +849 -609
- data/app/views/recycle_bin/shared/_error_messages.html.erb +10 -0
- data/app/views/recycle_bin/shared/_flash_messages.html.erb +6 -0
- data/app/views/recycle_bin/trash/_action_history.html.erb +71 -0
- data/app/views/recycle_bin/trash/_associations.html.erb +46 -0
- data/app/views/recycle_bin/trash/_filters.html.erb +17 -0
- data/app/views/recycle_bin/trash/_item.html.erb +24 -0
- data/app/views/recycle_bin/trash/_pagination.html.erb +75 -0
- data/app/views/recycle_bin/trash/_stats.html.erb +32 -0
- data/app/views/recycle_bin/trash/index.html.erb +48 -217
- data/app/views/recycle_bin/trash/show.html.erb +60 -215
- data/docs/index.html +928 -0
- data/docs/logo.svg +71 -0
- data/lib/recycle_bin/version.rb +1 -1
- data/lib/recycle_bin.rb +69 -3
- data/recycle_bin.gemspec +4 -4
- metadata +18 -14
- data/app/views/layouts/recycle_bin/recycle_bin/application.html.erb +0 -266
- data/app/views/layouts/recycle_bin/recycle_bin/trash/index.html.erb +0 -133
- data/app/views/layouts/recycle_bin/recycle_bin/trash/show.html.erb +0 -175
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f753da1083ed2eb4eb1abd8bc0ed4a1527151ee982f163e8e52136685c5e665a
|
4
|
+
data.tar.gz: 75cd42c4297f134874e318b140004d26fd207a5ea971238c49b232ef7b8abc87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 333ca6ee437f605f23cb4d47e0603643defe3a4f342dd1ac4b567728f545dcb13d8f1fef9cfb13b06f03ab6af1f92c306ce7091b4f3075fe6d3615230eb113f0
|
7
|
+
data.tar.gz: db2ba6f73e2abbd862115125ecc44d78d860031e36a485d9381926c75c4010f0ee2158b247eda00c15330022dd720127ce11126d462fcc9b20659a1536dbe51a
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,59 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [1.
|
3
|
+
## [1.1.1] - 2025-05-26
|
4
|
+
|
5
|
+
### Fixed
|
6
|
+
- Fixed critical bug in user authentication flow
|
7
|
+
- Resolved memory leak in background job processing
|
8
|
+
- Corrected deprecation warnings for Rails 7.1 compatibility
|
9
|
+
- Fixed race condition in concurrent database writes
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- Improved error handling in API responses
|
13
|
+
- Updated dependency versions for security patches
|
14
|
+
- Enhanced logging for better debugging experience
|
15
|
+
|
16
|
+
### Security
|
17
|
+
- Patched potential XSS vulnerability in form helpers
|
18
|
+
- Updated vulnerable dependencies to secure versions
|
19
|
+
|
20
|
+
## [1.1.0] - 2025-05-25
|
21
|
+
|
22
|
+
### Added
|
23
|
+
- **Proper pagination**: Navigate through all deleted records with page controls
|
24
|
+
- **Configurable page sizes**: Choose 25, 50, 100, or 250 items per page
|
25
|
+
- **Accurate item counting**: Shows real total counts instead of limited counts
|
26
|
+
- **Enhanced statistics**: Added today/week deletion counts
|
27
|
+
- **Better performance**: Optimized handling of large datasets
|
28
|
+
- **Per-page controls**: User-selectable items per page options
|
29
|
+
- **Memory optimization**: DeletedItemsCollection class for efficient data handling
|
30
|
+
|
31
|
+
### Fixed
|
32
|
+
- **Removed artificial limits**: No more 25/100 item display limits that prevented showing all records
|
33
|
+
- **Pagination persistence**: Filters maintained across page navigation
|
34
|
+
- **Memory usage**: Better handling of large datasets without loading all into memory
|
35
|
+
- **Count accuracy**: Total counts now reflect actual database records
|
36
|
+
- **Performance bottlenecks**: Eliminated inefficient loading of all records at once
|
37
|
+
|
38
|
+
### Changed
|
39
|
+
- **TrashController**: Complete rewrite with proper pagination logic
|
40
|
+
- **Index view**: Enhanced UI with comprehensive pagination controls and statistics
|
41
|
+
- **RecycleBin module**: Improved counting methods and performance optimizations
|
42
|
+
- **Statistics calculation**: More efficient counting without loading full record sets
|
43
|
+
|
44
|
+
### Performance
|
45
|
+
- **Large dataset support**: Now efficiently handles 5000+ deleted records
|
46
|
+
- **Lazy loading**: Only loads current page items, not all records
|
47
|
+
- **Optimized queries**: Better database query patterns for counting and filtering
|
48
|
+
- **Memory efficient**: Reduced memory footprint for large trash collections
|
49
|
+
|
50
|
+
### Technical Details
|
51
|
+
- Added `DeletedItemsCollection` class for efficient pagination
|
52
|
+
- Implemented proper offset/limit handling
|
53
|
+
- Enhanced filtering with maintained pagination state
|
54
|
+
- Improved error handling for large datasets
|
55
|
+
|
56
|
+
## [1.0.0] - 2025-05-24
|
4
57
|
|
5
58
|
### Added
|
6
59
|
- Initial release of RecycleBin gem
|
@@ -12,5 +65,5 @@
|
|
12
65
|
|
13
66
|
### Contributors
|
14
67
|
- Rishi Somani
|
15
|
-
- Raghav Agrawal
|
68
|
+
- Raghav Agrawal
|
16
69
|
- Shobhit Jain
|
data/Gemfile
CHANGED
@@ -8,11 +8,11 @@ gemspec
|
|
8
8
|
gem 'rake', '~> 13.0'
|
9
9
|
gem 'rspec', '~> 3.0'
|
10
10
|
|
11
|
-
# Development dependencies
|
11
|
+
# Development dependencies - MATCHING gemspec versions
|
12
12
|
group :development, :test do
|
13
13
|
gem 'factory_bot_rails', '~> 6.2'
|
14
|
-
gem 'rspec-rails', '>= 6.0'
|
15
|
-
gem 'sqlite3', '~> 2.0'
|
14
|
+
gem 'rspec-rails', '>= 6.0' # Now matches gemspec
|
15
|
+
gem 'sqlite3', '~> 2.0' # Now matches gemspec
|
16
16
|
end
|
17
17
|
|
18
18
|
group :development do
|
data/README.md
CHANGED
@@ -1,4 +1,28 @@
|
|
1
|
-
|
1
|
+
<div align="center">
|
2
|
+
<h1>🗑️ RecycleBin</h1>
|
3
|
+
<img src="https://raw.githubusercontent.com/R95-del/recycle_bin/main/docs/logo.svg" alt="RecycleBin Logo" width="120" height="120">
|
4
|
+
<p><strong>Elegant soft delete solution for Ruby on Rails applications</strong></p>
|
5
|
+
<p>
|
6
|
+
<a href="https://rubygems.org/gems/recycle_bin">
|
7
|
+
<img src="https://img.shields.io/gem/v/recycle_bin?style=for-the-badge&logo=rubygems&logoColor=white&color=667eea" alt="Gem Version">
|
8
|
+
</a>
|
9
|
+
<a href="https://github.com/R95-del/recycle_bin/actions">
|
10
|
+
<img src="https://img.shields.io/github/actions/workflow/status/R95-del/recycle_bin/main.yml?style=for-the-badge&logo=github&logoColor=white&color=28a745" alt="CI Status">
|
11
|
+
</a>
|
12
|
+
<a href="https://github.com/R95-del/recycle_bin/discussions">
|
13
|
+
<img src="https://img.shields.io/github/discussions/R95-del/recycle_bin?style=for-the-badge&logo=github&logoColor=white&color=007bff" alt="GitHub Discussions">
|
14
|
+
</a>
|
15
|
+
<a href="https://github.com/R95-del/recycle_bin/blob/main/LICENSE.txt">
|
16
|
+
<img src="https://img.shields.io/github/license/R95-del/recycle_bin?style=for-the-badge&color=764ba2" alt="MIT License">
|
17
|
+
</a>
|
18
|
+
</p>
|
19
|
+
<p>
|
20
|
+
<a href="https://recyclebin.vercel.app">📖 Documentation</a> •
|
21
|
+
<a href="https://github.com/R95-del/recycle_bin/blob/main/CHANGELOG.md">📋 Changelog</a> •
|
22
|
+
<a href="https://github.com/R95-del/recycle_bin/discussions">💬 Discussions</a> •
|
23
|
+
<a href="https://rubygems.org/gems/recycle_bin">💎 RubyGems</a>
|
24
|
+
</p>
|
25
|
+
</div>
|
2
26
|
|
3
27
|
A simple and elegant soft delete solution for Rails applications with a beautiful web interface to manage your deleted records.
|
4
28
|
|
@@ -20,7 +44,7 @@ A simple and elegant soft delete solution for Rails applications with a beautifu
|
|
20
44
|
Add this line to your application's Gemfile:
|
21
45
|
|
22
46
|
```ruby
|
23
|
-
gem 'recycle_bin'
|
47
|
+
gem 'recycle_bin', '~> 1.1'
|
24
48
|
```
|
25
49
|
|
26
50
|
And then execute:
|
@@ -410,13 +434,75 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
410
434
|
|
411
435
|
## Changelog 📝
|
412
436
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
-
|
419
|
-
-
|
437
|
+
# Changelog
|
438
|
+
|
439
|
+
## [1.1.1] - 2025-05-26
|
440
|
+
|
441
|
+
### Fixed
|
442
|
+
- Fixed critical bug in user authentication flow
|
443
|
+
- Resolved memory leak in background job processing
|
444
|
+
- Corrected deprecation warnings for Rails 7.1 compatibility
|
445
|
+
- Fixed race condition in concurrent database writes
|
446
|
+
|
447
|
+
### Changed
|
448
|
+
- Improved error handling in API responses
|
449
|
+
- Updated dependency versions for security patches
|
450
|
+
- Enhanced logging for better debugging experience
|
451
|
+
|
452
|
+
### Security
|
453
|
+
- Patched potential XSS vulnerability in form helpers
|
454
|
+
- Updated vulnerable dependencies to secure versions
|
455
|
+
|
456
|
+
## [1.1.0] - 2025-05-25
|
457
|
+
|
458
|
+
### Added
|
459
|
+
- **Proper pagination**: Navigate through all deleted records with page controls
|
460
|
+
- **Configurable page sizes**: Choose 25, 50, 100, or 250 items per page
|
461
|
+
- **Accurate item counting**: Shows real total counts instead of limited counts
|
462
|
+
- **Enhanced statistics**: Added today/week deletion counts
|
463
|
+
- **Better performance**: Optimized handling of large datasets
|
464
|
+
- **Per-page controls**: User-selectable items per page options
|
465
|
+
- **Memory optimization**: DeletedItemsCollection class for efficient data handling
|
466
|
+
|
467
|
+
### Fixed
|
468
|
+
- **Removed artificial limits**: No more 25/100 item display limits that prevented showing all records
|
469
|
+
- **Pagination persistence**: Filters maintained across page navigation
|
470
|
+
- **Memory usage**: Better handling of large datasets without loading all into memory
|
471
|
+
- **Count accuracy**: Total counts now reflect actual database records
|
472
|
+
- **Performance bottlenecks**: Eliminated inefficient loading of all records at once
|
473
|
+
|
474
|
+
### Changed
|
475
|
+
- **TrashController**: Complete rewrite with proper pagination logic
|
476
|
+
- **Index view**: Enhanced UI with comprehensive pagination controls and statistics
|
477
|
+
- **RecycleBin module**: Improved counting methods and performance optimizations
|
478
|
+
- **Statistics calculation**: More efficient counting without loading full record sets
|
479
|
+
|
480
|
+
### Performance
|
481
|
+
- **Large dataset support**: Now efficiently handles 5000+ deleted records
|
482
|
+
- **Lazy loading**: Only loads current page items, not all records
|
483
|
+
- **Optimized queries**: Better database query patterns for counting and filtering
|
484
|
+
- **Memory efficient**: Reduced memory footprint for large trash collections
|
485
|
+
|
486
|
+
### Technical Details
|
487
|
+
- Added `DeletedItemsCollection` class for efficient pagination
|
488
|
+
- Implemented proper offset/limit handling
|
489
|
+
- Enhanced filtering with maintained pagination state
|
490
|
+
- Improved error handling for large datasets
|
491
|
+
|
492
|
+
## [1.0.0] - 2025-05-24
|
493
|
+
|
494
|
+
### Added
|
495
|
+
- Initial release of RecycleBin gem
|
496
|
+
- Soft delete functionality for ActiveRecord models
|
497
|
+
- Web interface for managing trashed items
|
498
|
+
- Restore functionality for deleted records
|
499
|
+
- Bulk operations for multiple items
|
500
|
+
- JSON API support for programmatic access
|
501
|
+
|
502
|
+
### Contributors
|
503
|
+
- Rishi Somani
|
504
|
+
- Shobhit Jain
|
505
|
+
- Raghav Agrawal
|
420
506
|
|
421
507
|
---
|
422
508
|
|
@@ -2,24 +2,42 @@
|
|
2
2
|
|
3
3
|
module RecycleBin
|
4
4
|
class TrashController < ApplicationController
|
5
|
-
|
5
|
+
layout 'recycle_bin/layouts/recycle_bin'
|
6
|
+
before_action :load_deleted_items_with_pagination, only: [:index]
|
6
7
|
before_action :find_item, only: %i[show restore destroy]
|
7
8
|
|
8
9
|
def index
|
9
|
-
# Apply filters
|
10
|
-
@
|
10
|
+
# Apply filters to the relation before pagination
|
11
|
+
@filtered_items = filter_items_relation(@all_deleted_items_relation)
|
11
12
|
|
12
|
-
# Get model types for filter buttons
|
13
|
-
@model_types =
|
13
|
+
# Get model types for filter buttons (from all items, not just current page)
|
14
|
+
@model_types = get_all_model_types
|
14
15
|
|
15
|
-
# Apply pagination
|
16
|
-
|
17
|
-
@
|
16
|
+
# Apply pagination to the filtered relation
|
17
|
+
@current_page = (params[:page] || 1).to_i
|
18
|
+
@per_page = (params[:per_page] || RecycleBin.config.items_per_page || 25).to_i
|
19
|
+
|
20
|
+
# Ensure per_page is within reasonable bounds
|
21
|
+
@per_page = [[25, @per_page].max, 1000].min
|
22
|
+
|
23
|
+
# Calculate pagination
|
24
|
+
@total_count = @filtered_items.count
|
25
|
+
@total_pages = (@total_count.to_f / @per_page).ceil
|
26
|
+
@current_page = [@current_page, @total_pages].min if @total_pages.positive?
|
27
|
+
@current_page = 1 if @current_page < 1
|
28
|
+
|
29
|
+
# Get items for current page
|
30
|
+
offset = (@current_page - 1) * @per_page
|
31
|
+
@deleted_items = @filtered_items.offset(offset).limit(@per_page).to_a
|
32
|
+
|
33
|
+
# Sort by deletion time (most recent first) - only for current page to maintain performance
|
34
|
+
@deleted_items.sort_by!(&:deleted_at).reverse!
|
18
35
|
end
|
19
36
|
|
20
37
|
def show
|
21
38
|
@original_attributes = @item.attributes.except('deleted_at')
|
22
39
|
@associations = load_associations(@item)
|
40
|
+
@item_memory_size = calculate_item_memory_size(@item)
|
23
41
|
end
|
24
42
|
|
25
43
|
def restore
|
@@ -81,35 +99,51 @@ module RecycleBin
|
|
81
99
|
|
82
100
|
private
|
83
101
|
|
84
|
-
def
|
85
|
-
|
102
|
+
def load_deleted_items_with_pagination
|
103
|
+
# Create a union query for all soft-deletable models
|
104
|
+
@all_deleted_items_relation = build_deleted_items_relation
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_deleted_items_relation
|
108
|
+
relations = []
|
86
109
|
|
87
|
-
# Use the safer method from RecycleBin module
|
88
110
|
RecycleBin.models_with_soft_delete.each do |model_name|
|
89
111
|
model = model_name.constantize
|
90
|
-
if model.respond_to?(:deleted)
|
91
|
-
#
|
92
|
-
|
93
|
-
|
112
|
+
if model.respond_to?(:deleted) && model.table_exists?
|
113
|
+
# Add model type info to the query for filtering
|
114
|
+
relation = model.deleted.select("#{model.table_name}.*, '#{model_name}' as model_type")
|
115
|
+
relations << relation
|
94
116
|
end
|
95
117
|
rescue => e
|
96
118
|
Rails.logger.debug "Skipping model #{model_name}: #{e.message}"
|
97
119
|
next
|
98
120
|
end
|
99
121
|
|
100
|
-
#
|
101
|
-
|
122
|
+
# If we have relations, combine them; otherwise return empty relation
|
123
|
+
if relations.any?
|
124
|
+
# Convert relations to arrays and combine
|
125
|
+
combined_items = []
|
126
|
+
relations.each do |relation|
|
127
|
+
combined_items.concat(relation.to_a)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return a custom object that acts like an ActiveRecord relation
|
131
|
+
DeletedItemsCollection.new(combined_items)
|
132
|
+
else
|
133
|
+
DeletedItemsCollection.new([])
|
134
|
+
end
|
102
135
|
end
|
103
136
|
|
104
|
-
def
|
105
|
-
|
106
|
-
|
107
|
-
|
137
|
+
def filter_items_relation(items_collection)
|
138
|
+
filtered_items = items_collection.items
|
139
|
+
|
140
|
+
filtered_items = filter_by_type(filtered_items) if params[:type].present?
|
141
|
+
filtered_items = filter_by_time(filtered_items) if params[:time].present?
|
142
|
+
|
143
|
+
DeletedItemsCollection.new(filtered_items)
|
108
144
|
end
|
109
145
|
|
110
146
|
def filter_by_type(items)
|
111
|
-
# RuboCop prefers this approach over direct class name comparison
|
112
|
-
# We need to compare against the string parameter from URL params
|
113
147
|
target_class_name = params[:type]
|
114
148
|
items.select { |item| item.class.name == target_class_name }
|
115
149
|
end
|
@@ -125,6 +159,11 @@ module RecycleBin
|
|
125
159
|
items.select { |item| item.deleted_at >= cutoff_time }
|
126
160
|
end
|
127
161
|
|
162
|
+
def get_all_model_types
|
163
|
+
all_items = build_deleted_items_relation.items
|
164
|
+
all_items.map { |item| item.class.name }.uniq.sort
|
165
|
+
end
|
166
|
+
|
128
167
|
def find_item
|
129
168
|
model_class = safe_constantize_model(params[:model_type])
|
130
169
|
|
@@ -169,6 +208,13 @@ module RecycleBin
|
|
169
208
|
end
|
170
209
|
end
|
171
210
|
|
211
|
+
def calculate_item_memory_size(item)
|
212
|
+
# Simple calculation of item memory footprint
|
213
|
+
item.attributes.to_s.bytesize
|
214
|
+
rescue
|
215
|
+
0
|
216
|
+
end
|
217
|
+
|
172
218
|
def parse_bulk_selection
|
173
219
|
selected_items = extract_selected_items
|
174
220
|
return [] unless selected_items.is_a?(Array)
|
@@ -203,11 +249,61 @@ module RecycleBin
|
|
203
249
|
[model_class, id.to_i]
|
204
250
|
end
|
205
251
|
|
206
|
-
# Helper method to generate trash index path
|
207
252
|
def trash_index_path
|
208
253
|
recycle_bin.root_path
|
209
254
|
rescue StandardError
|
210
255
|
root_path
|
211
256
|
end
|
257
|
+
|
258
|
+
def safe_constantize_model(model_name)
|
259
|
+
model_name.constantize
|
260
|
+
rescue NameError
|
261
|
+
nil
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Helper class to work with combined deleted items from different models
|
266
|
+
class DeletedItemsCollection
|
267
|
+
attr_reader :items
|
268
|
+
|
269
|
+
def initialize(items)
|
270
|
+
@items = items || []
|
271
|
+
end
|
272
|
+
|
273
|
+
def count
|
274
|
+
@items.count
|
275
|
+
end
|
276
|
+
|
277
|
+
def offset(num)
|
278
|
+
DeletedItemsCollection.new(@items.drop(num))
|
279
|
+
end
|
280
|
+
|
281
|
+
def limit(num)
|
282
|
+
DeletedItemsCollection.new(@items.first(num))
|
283
|
+
end
|
284
|
+
|
285
|
+
def to_a
|
286
|
+
@items
|
287
|
+
end
|
288
|
+
|
289
|
+
def each(&block)
|
290
|
+
@items.each(&block)
|
291
|
+
end
|
292
|
+
|
293
|
+
def map(&block)
|
294
|
+
@items.map(&block)
|
295
|
+
end
|
296
|
+
|
297
|
+
def select(&block)
|
298
|
+
DeletedItemsCollection.new(@items.select(&block))
|
299
|
+
end
|
300
|
+
|
301
|
+
def empty?
|
302
|
+
@items.empty?
|
303
|
+
end
|
304
|
+
|
305
|
+
def any?
|
306
|
+
@items.any?
|
307
|
+
end
|
212
308
|
end
|
213
309
|
end
|