routes-analyzer 0.1.1 → 0.1.4

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: e0df5dfa530f0ff7771563a035f35bd225a1b7d20e01c87aa626c87fa60a94a4
4
- data.tar.gz: 1683d8d3a06202ce56e266bdd20b0d8805a08fc9eac68d9041be507fe78b367a
3
+ metadata.gz: 79618d6dca3b9246b8023943d2863bc985e3d9674fd56e51aec84ad0c10ebf62
4
+ data.tar.gz: 07043a67f3c6011aacc34097476444e45c7749ed8134bd71b48bb29ffe47cdff
5
5
  SHA512:
6
- metadata.gz: ddec876f42e606cca4f39b24ff3c2d442ae1d4ec635de8e6abba2434be1ca22629abe98a24750c048559ce67de9ec7c6042bb8481f8a87790508fcda5e28165d
7
- data.tar.gz: 867674e3c3c49f0ed810d78b6871092261b815e5f6fe696de450973cadd9de6dd8ecdf7e759af0867245a8a2e92bba5612657f0f623110744d4db72dd5ea3f0e
6
+ metadata.gz: 86f3904c67a101f44776d2d583c1f818340b5f79218a9ac0297a3eca2045faaff4142218cdb8e8a1bc4ec68ac122918aa237845dd2ad8a068a4ee2a45804058b
7
+ data.tar.gz: 43bf9d60f739f769efe4bd35a628a30537298226da1b5b8457f98e726168718361f292663eaa47a1d811baac744d489278a0a969bcb0e13f3792c791be5a9b78
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # Routes::Analyzer
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/routes-analyzer.svg)](https://badge.fury.io/rb/routes-analyzer)
4
+
3
5
  A Ruby on Rails plugin that tracks and analyzes route usage in your application. It uses Redis to store route access patterns and provides insights into which routes are being used and which are not.
4
6
 
5
7
  ## Features
6
8
 
7
9
  - **Route Usage Tracking**: Automatically tracks which routes are accessed and how often
10
+ - **Smart Parameter Handling**: Routes with parameters (like `/users/:id`) are properly grouped under a single pattern instead of creating separate entries for each parameter value
8
11
  - **Redis Storage**: Uses Redis to store usage statistics efficiently
9
12
  - **Configurable Timeframe**: Set custom analysis periods (default 30 days)
10
13
  - **Comprehensive Reporting**: Shows both used and unused routes
@@ -109,12 +112,47 @@ Displays current configuration and tests Redis connectivity.
109
112
  ## How It Works
110
113
 
111
114
  1. **Middleware Integration**: The plugin automatically adds middleware to your Rails application
112
- 2. **Request Tracking**: Each HTTP request is analyzed to extract route information
113
- 3. **Redis Storage**: Usage data is stored in Redis with the following structure:
115
+ 2. **Route Filtering**: Only routes explicitly defined in `routes.rb` are tracked. This ensures that:
116
+ - Undefined routes (404 errors) are not tracked
117
+ - Catch-all routes that handle unknown paths don't pollute the data
118
+ - Only legitimate application routes are analyzed
119
+ 3. **Request Tracking**: Each valid HTTP request is analyzed to extract route information
120
+ 4. **Redis Storage**: Usage data is stored in Redis with the following structure:
114
121
  - Route path and HTTP method
115
122
  - Access count within the timeframe
116
123
  - Last access timestamp
117
- 4. **Data Expiration**: Redis keys automatically expire after the configured timeframe plus a buffer period
124
+ 5. **Data Expiration**: Redis keys automatically expire after the configured timeframe plus a buffer period
125
+
126
+ ## Route Detection
127
+
128
+ The middleware uses Rails' routing system to determine if a route is valid:
129
+
130
+ - **Path Parameters Check**: Verifies that Rails recognized the route and set path parameters
131
+ - **Route Recognition**: Uses `Rails.application.routes.recognize_path` to confirm the route exists in `routes.rb`
132
+ - **Error Handling**: Gracefully handles routing errors and invalid requests without tracking them
133
+
134
+ This approach ensures that only routes you've intentionally defined are included in the usage analysis.
135
+
136
+ ## Parameterized Route Handling
137
+
138
+ The gem intelligently handles routes with parameters by tracking them under their route pattern rather than individual parameter values:
139
+
140
+ - **Route Definition**: `/users/:id` in `routes.rb`
141
+ - **Actual Requests**: `/users/123`, `/users/456`, `/users/789`
142
+ - **Tracked As**: Single entry for `/users/:id` with combined statistics
143
+
144
+ This means that accessing `/users/123` three times and `/users/456` two times will show up as 5 total accesses to the `/users/:id` route pattern, not as separate routes.
145
+
146
+ **Example Output:**
147
+ ```
148
+ COUNT ROUTE METHOD CONTROLLER#ACTION
149
+ --------------------------------------------------------------
150
+ 15 /users/:id GET users#show
151
+ 8 /users/:id/profile GET users#profile
152
+ 23 /posts/:id GET posts#show
153
+ ```
154
+
155
+ This grouping provides much more meaningful insights into which route patterns are being used in your application.
118
156
 
119
157
  ## Data Structure
120
158
 
@@ -23,6 +23,9 @@ module Routes
23
23
  return false unless Routes::Analyzer.track_usage?
24
24
  return false unless env["action_controller.instance"]
25
25
 
26
+ # Check if the route is actually defined in routes.rb
27
+ return false unless route_defined_in_rails?(env)
28
+
26
29
  true
27
30
  rescue => e
28
31
  Rails.logger.warn "Routes::Analyzer: Failed to check tracking conditions: #{e.message}"
@@ -57,19 +60,49 @@ module Routes
57
60
  Rails.logger.warn "Routes::Analyzer: Failed to track route usage: #{e.message}"
58
61
  end
59
62
 
63
+ def route_defined_in_rails?(env)
64
+ request = Rack::Request.new(env)
65
+
66
+ # First check: if Rails didn't set path_parameters, it means the route wasn't recognized
67
+ # This happens when Rails can't match the request to any defined route
68
+ path_params = env["action_dispatch.request.path_parameters"]
69
+ return false unless path_params
70
+
71
+ # Second check: verify that Rails can recognize this path/method combination
72
+ # This ensures the route is actually defined in routes.rb and not just handled by a catch-all
73
+ route_exists = Rails.application.routes.recognize_path(
74
+ request.path_info,
75
+ method: request.request_method.downcase.to_sym
76
+ )
77
+
78
+ return true if route_exists
79
+ false
80
+ rescue ActionController::RoutingError, NoMethodError
81
+ # If recognize_path raises RoutingError, the route is not defined in routes.rb
82
+ # NoMethodError can occur if the controller/action doesn't exist
83
+ false
84
+ rescue => e
85
+ Rails.logger.warn "Routes::Analyzer: Error checking route definition: #{e.message}"
86
+ false
87
+ end
88
+
60
89
  def extract_route_info(env, request)
61
90
  # Get the matched route from Rails
62
91
  if env["action_controller.instance"]
63
92
  controller = env["action_controller.instance"]
64
93
  action = controller.action_name
65
94
  controller_name = controller.controller_name
95
+ method = request.request_method.upcase
96
+
97
+ # Find the route pattern instead of using the actual path
98
+ route_path = find_route_pattern(controller_name, action, method)
66
99
 
67
- # Build route pattern from request path, removing query parameters
68
- route_path = request.path_info
100
+ # Fallback to actual path if pattern not found
101
+ route_path ||= request.path_info
69
102
 
70
103
  {
71
104
  route: route_path,
72
- method: request.request_method.upcase,
105
+ method: method,
73
106
  controller: controller_name,
74
107
  action: action
75
108
  }
@@ -79,6 +112,23 @@ module Routes
79
112
  nil
80
113
  end
81
114
 
115
+ def find_route_pattern(controller_name, action, method)
116
+ return nil unless defined?(Rails) && Rails.application
117
+
118
+ Rails.application.routes.routes.each do |route|
119
+ if route.defaults[:controller] == controller_name &&
120
+ route.defaults[:action] == action &&
121
+ route.verb == method
122
+ return route.path.spec.to_s.gsub(/\(\.:format\)$/, "")
123
+ end
124
+ end
125
+
126
+ nil
127
+ rescue => e
128
+ Rails.logger.warn "Routes::Analyzer: Failed to find route pattern: #{e.message}"
129
+ nil
130
+ end
131
+
82
132
  def build_redis_key(route, method)
83
133
  "#{configuration.redis_key_prefix}:#{method}:#{route.gsub('/', ':')}"
84
134
  end
@@ -1,5 +1,5 @@
1
1
  module Routes
2
2
  module Analyzer
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.4"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: routes-analyzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregorio Galante