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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecca5bc61bc12faa00187f0a37d0f73eebd8658b1192e8b45d61e9f839cdbc48
4
- data.tar.gz: cf86c31ba03eeb84276afb3d213a436cb7a4d0d989037d6a2f22f6fab11bfb1c
3
+ metadata.gz: f753da1083ed2eb4eb1abd8bc0ed4a1527151ee982f163e8e52136685c5e665a
4
+ data.tar.gz: 75cd42c4297f134874e318b140004d26fd207a5ea971238c49b232ef7b8abc87
5
5
  SHA512:
6
- metadata.gz: dcea5e5846a8ae0377132fa8de1e6fb39b9e3566999ada4c396697a7ddc40eaea27a0569ede0c2d367e56849e334bf2ea1b4a1ef0c5ad68d83d49d9212c62883
7
- data.tar.gz: 40bf89241c9f86b8d2923c95f6bf03140dbc78a0c7fceccec451a433c3552e9021b15e293ec77e76f3f379ccbe901b1f12d05f2c347e1cc5a2bf4f37e2fcefe2
6
+ metadata.gz: 333ca6ee437f605f23cb4d47e0603643defe3a4f342dd1ac4b567728f545dcb13d8f1fef9cfb13b06f03ab6af1f92c306ce7091b4f3075fe6d3615230eb113f0
7
+ data.tar.gz: db2ba6f73e2abbd862115125ecc44d78d860031e36a485d9381926c75c4010f0ee2158b247eda00c15330022dd720127ce11126d462fcc9b20659a1536dbe51a
data/CHANGELOG.md CHANGED
@@ -1,6 +1,59 @@
1
1
  # Changelog
2
2
 
3
- ## [1.0.0] - 2025-05-25
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
- # RecycleBin 🗑️
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
- ### Version 0.1.0 (2025-05-24)
414
- - Initial release
415
- - Basic soft delete functionality
416
- - Web interface for managing deleted items
417
- - Rails generators for easy setup
418
- - Bulk operations support
419
- - Model filtering and statistics
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
- before_action :load_deleted_items, only: [:index]
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
- @deleted_items = filter_items(@deleted_items)
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 = @deleted_items.map { |item| item.class.name }.uniq.sort
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 (since @deleted_items is an Array, we need to handle this differently)
16
- items_per_page = RecycleBin.config.items_per_page || 25
17
- @deleted_items = @deleted_items.first(items_per_page)
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 load_deleted_items
85
- @deleted_items = []
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
- # Get up to 100 items per model to avoid memory issues
92
- deleted_records = model.deleted.limit(100).to_a
93
- @deleted_items.concat(deleted_records)
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
- # Sort by deletion time (most recent first)
101
- @deleted_items.sort_by!(&:deleted_at).reverse!
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 filter_items(items)
105
- items = filter_by_type(items) if params[:type].present?
106
- items = filter_by_time(items) if params[:time].present?
107
- items
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