whoisonline 0.1.3 → 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: 8d9ca4af0f12891b59ecbceb8666fbbb49d05043bc29bce86caeb85f1fa5d92d
4
- data.tar.gz: d87b7d98171a1b83793d6291c5ccaaf452a372d18554b532435522938486b5b2
3
+ metadata.gz: dcd954e1560a78b4047064f6b1359d22f159b08fd86f3c8cea97283f8a7f2210
4
+ data.tar.gz: '06558961aad1873ceb47cf7799049603a9994376a9a2a9ed0b54eeb43b688207'
5
5
  SHA512:
6
- metadata.gz: 889ddb36bc48126bac9d70df40140381cef90c66a083bc89c533e60b29d44bc117ff9bb1f4637a2f0b60fb6dd04b399fce74db9b232b32362e4a23bf88a0ff98
7
- data.tar.gz: 102ad2155cee722972f09558454f57abc61a652453ac70a05ace23833948ced1f0191b999eb313199a6f2c17be097fd53e7b2339d74e68364199dbffcc0e259e
6
+ metadata.gz: 139becc8c6d5cdd18578023ba4a9c751a6f9803ec2396d73a229e6421d4b21543d3de4327b37513cc9075c3c5f9deb21d1f4e0900a03e84ac24db374d219af71
7
+ data.tar.gz: a2bd79ab7b77f9524865030f2af74cc011187191d1403968e094a26ed663866fa83d6e2a9a1a41512e3bfb805e2c7f61afa43a46e76dc98e2b7a6aede6b8096c
data/README.md CHANGED
@@ -1,125 +1,356 @@
1
- # WhoIsOnline
1
+ # WhoIsOnline 💚
2
2
 
3
- Track "who is online right now?" in Rails 7+ using Redis TTL. No database writes, production-safe, and auto-hooks into controllers via a Rails Engine.
3
+ <div align="center">
4
4
 
5
- ## Features
6
- - Rails Engine auto-includes a controller concern to mark users online.
7
- - Works with `current_user` from any auth system (Devise, custom, etc.).
8
- - TTL-based presence in Redis, no tables required.
9
- - **Automatic offline detection** when users close their browser/tab.
10
- - **Visible-only heartbeats**: only ping while the tab is visible/active (configurable interval).
11
- - Throttled Redis writes to reduce load (configurable).
12
- - Safe SCAN-based counting; no `KEYS`.
13
- - Configurable Redis client, TTL, throttle duration, user id method, controller accessor, namespace, and heartbeat interval.
5
+ ![WhoIsOnline](https://img.shields.io/badge/WhoIsOnline-v0.1.3-brightgreen)
6
+ ![Rails](https://img.shields.io/badge/Rails-7%2B-red)
7
+ ![Ruby](https://img.shields.io/badge/Ruby-3.1%2B-red)
8
+ ![License](https://img.shields.io/badge/License-MIT-blue)
9
+ ![Gem](https://img.shields.io/gem/v/whoisonline?color=blue)
14
10
 
15
- ## Installation
16
- Add to your Gemfile:
11
+ **Track "who is online right now?" in Rails using Redis TTL. Zero database writes, production-ready, and auto-hooks into controllers.**
12
+
13
+ [Installation](#-installation) • [Quick Start](#-quick-start) • [Configuration](#-configuration) • [API](#-public-api) • [Examples](#-examples)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## ✨ Features
20
+
21
+ - 🚀 **Zero Setup** - Rails Engine auto-includes controller concern
22
+ - 🔌 **Works with Any Auth** - Devise, custom, or any `current_user` method
23
+ - ⚡ **Redis TTL-Based** - No database tables required
24
+ - 👁️ **Smart Tracking** - Only tracks when tab is visible/active
25
+ - 🔄 **Automatic Offline Detection** - Marks users offline when browser closes
26
+ - ⏱️ **Throttled Writes** - Configurable to reduce Redis load
27
+ - 🔍 **SCAN-Based** - Safe counting without blocking Redis (`KEYS` not used)
28
+ - 🎛️ **Highly Configurable** - Redis client, TTL, throttle, heartbeat interval, and more
29
+
30
+ ---
31
+
32
+ ## 📦 Installation
33
+
34
+ ### From RubyGems (Recommended)
35
+
36
+ Add to your `Gemfile`:
17
37
 
18
38
  ```ruby
19
- gem "whoisonline", github: "KapilDevPal/WhoIsOnline"
39
+ gem "whoisonline"
20
40
  ```
21
41
 
22
- Or install directly:
42
+ Then run:
23
43
 
24
44
  ```bash
25
- bundle add whoisonline
45
+ bundle install
26
46
  ```
27
47
 
28
- ## Quick Start
29
- Create an initializer `config/initializers/whoisonline.rb`:
48
+ ### From GitHub (Development)
49
+
50
+ ```ruby
51
+ gem "whoisonline", github: "KapilDevPal/WhoIsOnline"
52
+ ```
53
+
54
+ ---
55
+
56
+ ## 🚀 Quick Start
57
+
58
+ ### 1. Create Initializer
59
+
60
+ Create `config/initializers/whoisonline.rb`:
30
61
 
31
62
  ```ruby
32
63
  WhoIsOnline.configure do |config|
33
64
  config.redis = -> { Redis.new(url: ENV.fetch("REDIS_URL")) }
34
65
  config.ttl = 5.minutes
35
66
  config.throttle = 60.seconds
36
- config.user_id_method = :id
37
- config.heartbeat_interval = 60.seconds # client heartbeat when tab visible
67
+ config.heartbeat_interval = 60.seconds # Heartbeat when tab is visible
38
68
  end
39
69
  ```
40
70
 
41
- The engine auto-adds a concern that runs after each controller action to mark the `current_user` as online.
71
+ ### 2. Add to Layout (Optional but Recommended)
42
72
 
43
- **To enable offline detection when users close their browser**, add this to your main layout (e.g., `app/views/layouts/application.html.erb`):
73
+ Add to your main layout (`app/views/layouts/application.html.erb`):
44
74
 
45
75
  ```erb
46
- <%= whoisonline_offline_script %>
76
+ <!DOCTYPE html>
77
+ <html>
78
+ <head>
79
+ <title>My App</title>
80
+ <%= csrf_meta_tags %>
81
+ </head>
82
+ <body>
83
+ <%= yield %>
84
+ <%= whoisonline_offline_script %>
85
+ </body>
86
+ </html>
47
87
  ```
48
88
 
49
- This will automatically mark users offline when they close the browser/tab.
50
- Heartbeats run only when the tab is visible/active (interval: `heartbeat_interval`, default 60s), keeping the user online without constant polling.
89
+ **That's it!** The engine automatically tracks users online after each controller action.
90
+
91
+ ---
51
92
 
52
- ## Public API
53
- - `WhoIsOnline.track(user)` – mark a user online (auto-called by the controller concern).
54
- - `WhoIsOnline.offline(user)` – mark a user offline immediately.
55
- - `WhoIsOnline.online?(user)` boolean.
56
- - `WhoIsOnline.count` – number of online users (via SCAN).
57
- - `WhoIsOnline.user_ids` – array of ids (strings by default).
58
- - `WhoIsOnline.users(User)` ActiveRecord relation for convenience.
93
+ ## 📖 Public API
94
+
95
+ ```ruby
96
+ # Mark user online (auto-called by controller concern)
97
+ WhoIsOnline.track(user)
98
+
99
+ # Mark user offline immediately
100
+ WhoIsOnline.offline(user)
101
+
102
+ # Check if user is online
103
+ WhoIsOnline.online?(user) # => true/false
104
+
105
+ # Get count of online users
106
+ WhoIsOnline.count # => 42
107
+
108
+ # Get array of online user IDs
109
+ WhoIsOnline.user_ids # => ["1", "2", "3"]
110
+
111
+ # Get ActiveRecord relation of online users
112
+ WhoIsOnline.users(User) # => User.where(id: [...])
113
+ ```
114
+
115
+ ---
116
+
117
+ ## ⚙️ Configuration
59
118
 
60
- ## Configuration
61
119
  ```ruby
62
120
  WhoIsOnline.configure do |config|
121
+ # Redis connection (required)
63
122
  config.redis = -> { Redis.new(url: ENV.fetch("REDIS_URL", "redis://127.0.0.1:6379/0")) }
64
- config.ttl = 5.minutes # how long a user stays online without activity
65
- config.throttle = 60.seconds # minimum time between Redis writes per user
66
- config.user_id_method = :id # how to pull an ID from the user object
67
- config.current_user_method = :current_user # method on controllers
68
- config.heartbeat_interval = 60.seconds # heartbeat frequency while tab visible
69
- config.namespace = "whoisonline:user"
70
- config.auto_hook = true # disable if you prefer manual tracking
71
- config.logger = Rails.logger if defined?(Rails)
123
+
124
+ # TTL settings
125
+ config.ttl = 5.minutes # How long user stays online without activity
126
+ config.throttle = 60.seconds # Minimum time between Redis writes per user
127
+
128
+ # User identification
129
+ config.user_id_method = :id # Method to get user ID
130
+ config.current_user_method = :current_user # Method on controllers to get user
131
+
132
+ # Heartbeat (for visible tab tracking)
133
+ config.heartbeat_interval = 60.seconds # Heartbeat frequency when tab is visible
134
+
135
+ # Advanced
136
+ config.namespace = "whoisonline:user" # Redis key namespace
137
+ config.auto_hook = true # Auto-include controller concern
138
+ config.logger = Rails.logger # Logger instance
139
+ end
140
+ ```
141
+
142
+ ### Configuration Options
143
+
144
+ | Option | Default | Description |
145
+ |--------|---------|-------------|
146
+ | `ttl` | `5.minutes` | How long a user stays online without activity |
147
+ | `throttle` | `60.seconds` | Minimum time between Redis writes per user |
148
+ | `heartbeat_interval` | `60.seconds` | Heartbeat frequency when tab is visible |
149
+ | `user_id_method` | `:id` | Method to extract ID from user object |
150
+ | `current_user_method` | `:current_user` | Method name on controllers |
151
+ | `namespace` | `"whoisonline:user"` | Redis key namespace prefix |
152
+ | `auto_hook` | `true` | Auto-include controller concern |
153
+ | `logger` | `Rails.logger` | Logger for errors/warnings |
154
+
155
+ ---
156
+
157
+ ## 💡 Examples
158
+
159
+ ### Basic Usage
160
+
161
+ ```ruby
162
+ # In a controller (automatic via engine)
163
+ # Users are tracked after each action
164
+
165
+ # Check if user is online
166
+ if WhoIsOnline.online?(current_user)
167
+ # User is currently online
72
168
  end
169
+
170
+ # Get online users count
171
+ @online_count = WhoIsOnline.count
172
+
173
+ # Get online users
174
+ @online_users = WhoIsOnline.users(User)
73
175
  ```
74
176
 
75
- ## Performance Notes
76
- - Uses `SET key value EX ttl` for O(1) writes.
77
- - Throttling prevents hot users from spamming Redis.
78
- - Counting and user listing use `SCAN` to avoid blocking Redis (`KEYS` is not used).
79
- - Namespace keeps presence keys isolated; use a dedicated Redis db/cluster for large scale.
177
+ ### Manual Tracking
80
178
 
81
- ## Example Usage in Rails
82
179
  ```ruby
83
- # Somewhere in your controller you can also call manually:
180
+ # Manually mark user online
84
181
  WhoIsOnline.track(current_user)
85
182
 
86
- # Mark user offline (e.g., on logout)
183
+ # Manually mark user offline (e.g., on logout)
87
184
  WhoIsOnline.offline(current_user)
185
+ ```
88
186
 
89
- # In a background job
90
- if WhoIsOnline.online?(user)
91
- # notify
92
- end
187
+ ### In Background Jobs
93
188
 
94
- # In a dashboard
95
- @online_users = WhoIsOnline.users(User).order(last_sign_in_at: :desc)
96
- @online_count = WhoIsOnline.count
189
+ ```ruby
190
+ class NotificationJob < ApplicationJob
191
+ def perform(user_id)
192
+ user = User.find(user_id)
193
+
194
+ if WhoIsOnline.online?(user)
195
+ # Only notify if user is online
196
+ NotificationService.deliver(user)
197
+ end
198
+ end
199
+ end
97
200
  ```
98
201
 
99
- ### Layout Example
100
- In your main layout (`app/views/layouts/application.html.erb`):
202
+ ### Dashboard View
203
+
204
+ ```ruby
205
+ # In your controller
206
+ class DashboardController < ApplicationController
207
+ def index
208
+ @online_count = WhoIsOnline.count
209
+ @online_users = WhoIsOnline.users(User)
210
+ .order(last_sign_in_at: :desc)
211
+ .limit(50)
212
+ end
213
+ end
214
+ ```
101
215
 
102
216
  ```erb
103
- <!DOCTYPE html>
104
- <html>
105
- <head>
106
- <title>My App</title>
107
- <%= csrf_meta_tags %>
108
- </head>
109
- <body>
110
- <%= yield %>
111
- <%= whoisonline_offline_script %>
112
- </body>
113
- </html>
217
+ <!-- In your view -->
218
+ <div class="online-users">
219
+ <h2>Online Now (<%= @online_count %>)</h2>
220
+ <ul>
221
+ <% @online_users.each do |user| %>
222
+ <li><%= user.name %> <span class="badge">●</span></li>
223
+ <% end %>
224
+ </ul>
225
+ </div>
226
+ ```
227
+
228
+ ---
229
+
230
+ ## 🎯 How It Works
231
+
232
+ 1. **Controller Action** - After each action, the engine automatically calls `WhoIsOnline.track(current_user)`
233
+ 2. **Redis Write** - User presence is stored in Redis with TTL: `SET whoisonline:user:123 <timestamp> EX 300`
234
+ 3. **Throttling** - Writes are throttled per user to prevent Redis spam
235
+ 4. **Heartbeat** - When tab is visible, JavaScript sends periodic heartbeats to keep user online
236
+ 5. **Offline Detection** - When browser closes, JavaScript sends offline request
237
+ 6. **TTL Expiry** - If no activity, Redis key expires automatically
238
+
239
+ ---
240
+
241
+ ## ⚡ Performance
242
+
243
+ - **O(1) Writes** - Uses `SET key value EX ttl` for constant-time operations
244
+ - **Throttled** - Prevents hot users from spamming Redis
245
+ - **SCAN-Based** - Counting uses `SCAN` instead of `KEYS` (non-blocking)
246
+ - **Namespace Isolation** - Keys are namespaced for easy management
247
+ - **No Database** - Zero database writes, all in Redis
248
+
249
+ ### Recommended Settings
250
+
251
+ For **high-traffic** applications:
252
+
253
+ ```ruby
254
+ config.ttl = 2.minutes # Shorter TTL = more accurate
255
+ config.throttle = 30.seconds # More frequent updates
256
+ config.heartbeat_interval = 30.seconds # More frequent heartbeats
257
+ ```
258
+
259
+ For **low-traffic** applications:
260
+
261
+ ```ruby
262
+ config.ttl = 10.minutes # Longer TTL = less Redis activity
263
+ config.throttle = 120.seconds # Less frequent updates
264
+ config.heartbeat_interval = 120.seconds # Less frequent heartbeats
265
+ ```
266
+
267
+ ---
268
+
269
+ ## 🔧 Troubleshooting
270
+
271
+ ### Users Not Showing as Online
272
+
273
+ 1. Check Redis connection: `redis-cli ping`
274
+ 2. Verify `current_user` method exists in your controllers
275
+ 3. Check logs for errors: `tail -f log/development.log`
276
+ 4. Verify TTL hasn't expired: `redis-cli TTL whoisonline:user:1`
277
+
278
+ ### Helper Not Available
279
+
280
+ If `whoisonline_offline_script` is not available:
281
+
282
+ 1. Restart Rails server
283
+ 2. Check that gem is loaded: `bundle list | grep whoisonline`
284
+ 3. Verify engine is loaded: Check `config/application.rb` for engine loading
285
+
286
+ ### Heartbeat Not Working
287
+
288
+ 1. Check browser console for JavaScript errors
289
+ 2. Verify CSRF token is present: `<%= csrf_meta_tags %>`
290
+ 3. Check network tab for heartbeat requests
291
+ 4. Verify `heartbeat_interval` is configured
292
+
293
+ ---
294
+
295
+ ## 🛠️ Extensibility
296
+
297
+ The gem is designed to be extensible:
298
+
299
+ - **ActionCable Integration** - Broadcast presence changes
300
+ - **Custom Events** - Hook into track/offline events
301
+ - **Multiple Redis Instances** - Use different Redis for presence
302
+ - **Custom User Models** - Works with any user model structure
303
+
304
+ Example: ActionCable Integration
305
+
306
+ ```ruby
307
+ # In an initializer
308
+ WhoIsOnline.tracker.define_singleton_method(:track) do |user|
309
+ super(user)
310
+ ActionCable.server.broadcast("presence", { user_id: user.id, status: "online" })
311
+ end
114
312
  ```
115
313
 
116
- ## Extensibility
117
- - Engine-based hook is easy to extend (e.g., add ActionCable broadcast).
118
- - Tracker service is isolated and unit-testable.
119
- - Configuration is thread-safe and lazy-instantiated.
314
+ ---
315
+
316
+ ## 📝 License
317
+
318
+ MIT License - see [LICENSE](LICENSE) file for details.
319
+
320
+ ---
321
+
322
+ ## 👤 Author
323
+
324
+ **Kapil Dev Pal**
325
+
326
+ - 📧 Email: dev.kapildevpal@gmail.com
327
+ - 🐦 Twitter: [@rails_to_rescue](https://twitter.com/rails_to_rescue)
328
+ - 🚀 Project: [rails_to_rescue](https://github.com/rails-to-rescue)
329
+
330
+ ---
331
+
332
+ ## 🤝 Contributing
333
+
334
+ Contributions are welcome! Please feel free to submit a Pull Request.
335
+
336
+ 1. Fork the repository
337
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
338
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
339
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
340
+ 5. Open a Pull Request
341
+
342
+ ---
343
+
344
+ ## ⭐ Show Your Support
345
+
346
+ If you find this gem useful, please give it a ⭐ on GitHub!
347
+
348
+ ---
349
+
350
+ <div align="center">
120
351
 
121
- ## Author
122
- - Kapil Dev Pal – dev.kapildevpal@gmail.com / @rails_to_rescue
123
- - Project: rails_to_rescue
352
+ **Made with ❤️ for the Rails community**
124
353
 
354
+ [Report Bug](https://github.com/KapilDevPal/WhoIsOnline/issues) • [Request Feature](https://github.com/KapilDevPal/WhoIsOnline/issues) • [View on GitHub](https://github.com/KapilDevPal/WhoIsOnline)
125
355
 
356
+ </div>
@@ -21,6 +21,9 @@ module WhoIsOnline
21
21
 
22
22
  initializer "whoisonline.helpers" do
23
23
  ActiveSupport.on_load(:action_view) do
24
+ # Explicitly require the helper module from app directory
25
+ helper_path = File.join(Engine.root, "app", "helpers", "whoisonline", "application_helper.rb")
26
+ require helper_path if File.exist?(helper_path)
24
27
  include WhoIsOnline::ApplicationHelper
25
28
  end
26
29
  end
@@ -1,5 +1,5 @@
1
1
  module WhoIsOnline
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
4
4
 
5
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whoisonline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kapil Dev Pal
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-27 00:00:00.000000000 Z
11
+ date: 2025-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport