flu-rails 8.0.0 → 8.0.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 +27 -1
- data/README.md +30 -6
- data/flu-rails.gemspec +39 -0
- data/lib/flu-rails/action_controller_extender.rb +31 -27
- data/lib/flu-rails/event_factory.rb +3 -1
- data/lib/flu-rails/util.rb +12 -3
- data/lib/flu-rails/version.rb +1 -1
- data/lib/flu-rails.rb +4 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fde08f865924f75af0fc55c572bb6d10c617275772848055f838234cbf64a515
|
|
4
|
+
data.tar.gz: f675884b945492c91c6dbb8713156e2559da185d3b585aac2598525f61ae0d3d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4084a87a8b3ac4b9b3de65b6fd3e0c0c2cf6cc912afcb0570212dc38baa706fac873033cda2fd38e177659c62d0fe8e5f7fef941feee8419874b9064d865b32b
|
|
7
|
+
data.tar.gz: c4648f491c6d74e4f0a48cbcc5cedd164aee43b9e615f6c51108fdb5390869a96332b758a87c9b1203a65d9b96e35f7061e0bee317ed94b76535b26aa00add34
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,33 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
### [8.0.
|
|
8
|
+
### [8.0.2] - 2026-08-01
|
|
9
|
+
|
|
10
|
+
**Fixed**
|
|
11
|
+
|
|
12
|
+
* Honour `configuration.logger` when rejecting a request on its user agent.
|
|
13
|
+
* Stop defining those helpers on `ActionController::Base` and `ActionController::API` themselves.
|
|
14
|
+
* Apply the model's `emitter:` override when exporting existing entities. `Util::ExportService`
|
|
15
|
+
passed `nil` instead of the model's lambda, so a replayed event carried the global
|
|
16
|
+
`application_name` while the live event for the same entity carried the overriden one — putting
|
|
17
|
+
the two on different routing keys. Unnoticed since `1.0.4`, where the option was introduced.
|
|
18
|
+
* Do not assume that a defined `Rails` constant means railties is loaded.
|
|
19
|
+
|
|
20
|
+
**Changed**
|
|
21
|
+
|
|
22
|
+
* Stop publishing `overriden_emitter` as part of the event payload.
|
|
23
|
+
|
|
24
|
+
**Tests**
|
|
25
|
+
|
|
26
|
+
* Enable the three controller examples that were disabled with `xit`, and run them through the real
|
|
27
|
+
`ActionController` dispatch, which is what triggers the callbacks registered by `track_requests`.
|
|
28
|
+
This is the code path that hid the `ActionController::UnfilteredParameters` bug fixed in `8.0.1`.
|
|
29
|
+
* Cover `Util::ExportService`, which had no test at all — and which is how the `emitter:` bug above
|
|
30
|
+
surfaced.
|
|
31
|
+
* Make the spec setup idempotent
|
|
32
|
+
* Integration tests with RabbitMQ
|
|
33
|
+
|
|
34
|
+
### [8.0.1] - 2026-07-31
|
|
9
35
|
|
|
10
36
|
**Fixed**
|
|
11
37
|
|
data/README.md
CHANGED
|
@@ -40,7 +40,9 @@ Each configuration is detailed below.
|
|
|
40
40
|
* Ruby >= 3.2 (tested against 3.2, 3.3 and 3.4)
|
|
41
41
|
* Rails 8 only (`activerecord`, `actionpack` and `activesupport` are runtime dependencies,
|
|
42
42
|
constrained to `~> 8.0`). `flu-rails` extends `ActiveRecord::Base` and `ActionController::Base`, so it requires Rails.
|
|
43
|
-
*
|
|
43
|
+
* RabbitMQ: no specific version is required by `flu-rails` itself. The broker is reached through
|
|
44
|
+
`bunny` 3.x and `rabbitmq_http_api_client` 3.x, which target the
|
|
45
|
+
[currently supported RabbitMQ release series](https://www.rabbitmq.com/release-information).
|
|
44
46
|
|
|
45
47
|
## Usage
|
|
46
48
|
|
|
@@ -171,10 +173,32 @@ All options have a default value. However, all of them can be changed in your in
|
|
|
171
173
|
From the `flu-rails` directory:
|
|
172
174
|
|
|
173
175
|
```
|
|
174
|
-
$ docker
|
|
175
|
-
$ docker run -v `pwd`:/usr/src/app/ flu:test rspec spec
|
|
176
|
+
$ docker compose run --rm specs
|
|
176
177
|
```
|
|
177
178
|
|
|
179
|
+
This starts a RabbitMQ broker, waits for it, and runs the whole suite against it.
|
|
180
|
+
|
|
181
|
+
Part of the suite publishes to a real broker and drives its HTTP management API: nothing there is
|
|
182
|
+
stubbed, since a stub cannot tell whether the gem actually speaks AMQP. To run the specs directly on
|
|
183
|
+
your machine, start a broker first:
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
$ docker compose up -d rabbitmq
|
|
187
|
+
$ bundle exec rspec
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Without one, those examples are reported as skipped and the rest of the suite still runs. Set
|
|
191
|
+
`FLU_REQUIRE_RABBITMQ` to turn that skip into a failure — this is what the CI workflow does, so that
|
|
192
|
+
a build cannot report success without having reached RabbitMQ:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
$ FLU_REQUIRE_RABBITMQ=true bundle exec rspec
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
A broker of your own can be used instead through `FLU_RABBITMQ_HOST`, `FLU_RABBITMQ_PORT`,
|
|
199
|
+
`FLU_RABBITMQ_MANAGEMENT_PORT`, `FLU_RABBITMQ_USER` and `FLU_RABBITMQ_PASSWORD`. Every example
|
|
200
|
+
declares an exchange and queues of its own, and deletes them afterwards.
|
|
201
|
+
|
|
178
202
|
## Example of Events
|
|
179
203
|
|
|
180
204
|
### Structure of an Active Record change
|
|
@@ -276,12 +300,12 @@ no API key is stored in this repository, the workflow exchanges a short-lived Gi
|
|
|
276
300
|
scoped RubyGems credential.
|
|
277
301
|
|
|
278
302
|
1. Update `Flu::VERSION` in `lib/flu-rails/version.rb` and the `CHANGELOG.md`
|
|
279
|
-
2. Commit and push these changes to `
|
|
303
|
+
2. Commit and push these changes to `main`
|
|
280
304
|
3. Tag the commit and push the tag:
|
|
281
305
|
|
|
282
306
|
```
|
|
283
|
-
$ git tag -a v8.0.
|
|
284
|
-
$ git push origin v8.0.
|
|
307
|
+
$ git tag -a v8.0.2 -m "Version 8.0.2"
|
|
308
|
+
$ git push origin v8.0.2
|
|
285
309
|
```
|
|
286
310
|
|
|
287
311
|
The workflow then checks that the tag matches `Flu::VERSION`, runs the tests, builds the gem
|
data/flu-rails.gemspec
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require_relative "lib/flu-rails/version"
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "flu-rails"
|
|
5
|
+
spec.version = Flu::VERSION
|
|
6
|
+
spec.authors = ["Loïc Vigneron", "Lorent Lempereur", "Thibault Poncelet", "Logan Clément"]
|
|
7
|
+
spec.email = ["support@commuty.net"]
|
|
8
|
+
spec.summary = "Track your application events and publish them to RabbitMQ."
|
|
9
|
+
spec.description = "Seamlessly emit events from an existing Rails application, without changing its " \
|
|
10
|
+
"codebase, and publish them to RabbitMQ. Events are generated from CRUD operations " \
|
|
11
|
+
"on ActiveRecord models and from requests on Rails controller actions."
|
|
12
|
+
spec.homepage = "https://github.com/crepesourcing/flu-rails"
|
|
13
|
+
spec.license = "MIT"
|
|
14
|
+
|
|
15
|
+
spec.required_ruby_version = ">= 3.2"
|
|
16
|
+
|
|
17
|
+
spec.metadata = {
|
|
18
|
+
"source_code_uri" => spec.homepage,
|
|
19
|
+
"changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md",
|
|
20
|
+
"bug_tracker_uri" => "#{spec.homepage}/issues",
|
|
21
|
+
"rubygems_mfa_required" => "true"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
spec.files = Dir.glob(["lib/**/*.rb", "CHANGELOG.md", "MIT-LICENSE", "README.md", "flu-rails.gemspec"])
|
|
25
|
+
spec.require_paths = ["lib"]
|
|
26
|
+
|
|
27
|
+
spec.add_dependency "actionpack", "~> 8.0"
|
|
28
|
+
spec.add_dependency "activerecord", "~> 8.0"
|
|
29
|
+
spec.add_dependency "activesupport", "~> 8.0"
|
|
30
|
+
spec.add_dependency "bunny", "~> 3.1"
|
|
31
|
+
spec.add_dependency "logger", "~> 1.7"
|
|
32
|
+
spec.add_dependency "rabbitmq_http_api_client", "~> 3.2"
|
|
33
|
+
|
|
34
|
+
spec.add_development_dependency "byebug", "~> 13.0"
|
|
35
|
+
spec.add_development_dependency "ostruct", "~> 0.6"
|
|
36
|
+
spec.add_development_dependency "rake", ">= 13.0"
|
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.13"
|
|
38
|
+
spec.add_development_dependency "sqlite3", "~> 2.9"
|
|
39
|
+
end
|
|
@@ -21,49 +21,38 @@ module Flu
|
|
|
21
21
|
ignored_request_params = options.fetch(:ignored_request_params, []).map(&:to_sym)
|
|
22
22
|
emitter_lambda = options[:emitter]
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
prepend_after_action do
|
|
32
|
-
track_requests(event_factory, event_publisher, user_metadata_lambda, ignored_request_params, emitter_lambda)
|
|
33
|
-
remove_request_entity_metadata_lambda
|
|
34
|
-
end
|
|
35
|
-
after_action do
|
|
36
|
-
remove_request_id
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def define_request_id
|
|
24
|
+
# These helpers are defined with 'define_method' rather than 'def' for two reasons. A bare
|
|
25
|
+
# 'def' opens a new scope, so it captures neither 'logger' nor the tracking options: the
|
|
26
|
+
# former silently resolved to ActionController::Base#logger, which ignored 'Flu.config.logger'
|
|
27
|
+
# altogether. And its default definee is the class 'class_eval' was called on, so the helpers
|
|
28
|
+
# landed on ActionController::Base itself, leaking onto every controller of the host
|
|
29
|
+
# application. Here 'self' is the class calling 'track_requests', which is where they belong.
|
|
30
|
+
define_method(:flu_define_request_id) do
|
|
40
31
|
request_id = SecureRandom.uuid
|
|
41
32
|
@flu_request_id = request_id
|
|
42
33
|
Flu::CoreExt.flu_tracker_request_id = request_id
|
|
43
34
|
end
|
|
44
35
|
|
|
45
|
-
|
|
36
|
+
define_method(:flu_remove_request_id) do
|
|
46
37
|
Flu::CoreExt.flu_tracker_request_id = nil
|
|
47
38
|
end
|
|
48
39
|
|
|
49
|
-
|
|
40
|
+
define_method(:flu_define_request_entity_metadata) do
|
|
50
41
|
Flu::CoreExt.flu_tracker_request_entity_metadata = instance_exec(&entity_metadata_lambda) if entity_metadata_lambda
|
|
51
42
|
end
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
define_method(:flu_remove_request_entity_metadata) do
|
|
54
45
|
Flu::CoreExt.flu_tracker_request_entity_metadata = nil
|
|
55
46
|
end
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
rejected_user_agents
|
|
59
|
-
|
|
60
|
-
matching_user_agents = user_agent&.match(rejected_user_agents)
|
|
61
|
-
!matching_user_agents.nil?
|
|
48
|
+
define_method(:flu_rejected_origin?) do
|
|
49
|
+
rejected_user_agents = Regexp.union(Flu.config.rejected_user_agents)
|
|
50
|
+
!request.user_agent&.match(rejected_user_agents).nil?
|
|
62
51
|
end
|
|
63
52
|
|
|
64
|
-
|
|
65
|
-
if
|
|
66
|
-
logger.warn
|
|
53
|
+
define_method(:flu_track_request) do
|
|
54
|
+
if flu_rejected_origin?
|
|
55
|
+
logger.warn("Origin user agent rejected: #{request.user_agent}")
|
|
67
56
|
else
|
|
68
57
|
tracked_request = event_factory.create_data_from_request(@flu_request_id,
|
|
69
58
|
params,
|
|
@@ -77,6 +66,21 @@ module Flu
|
|
|
77
66
|
event_publisher.publish(event)
|
|
78
67
|
end
|
|
79
68
|
end
|
|
69
|
+
|
|
70
|
+
before_action do
|
|
71
|
+
flu_define_request_id
|
|
72
|
+
@request_start_time = Time.zone.now
|
|
73
|
+
end
|
|
74
|
+
prepend_before_action do
|
|
75
|
+
flu_define_request_entity_metadata
|
|
76
|
+
end
|
|
77
|
+
prepend_after_action do
|
|
78
|
+
flu_track_request
|
|
79
|
+
flu_remove_request_entity_metadata
|
|
80
|
+
end
|
|
81
|
+
after_action do
|
|
82
|
+
flu_remove_request_id
|
|
83
|
+
end
|
|
80
84
|
end
|
|
81
85
|
end
|
|
82
86
|
end
|
|
@@ -48,7 +48,9 @@ module Flu
|
|
|
48
48
|
original_emitter = @emitter
|
|
49
49
|
overriden_emitter = data[:overriden_emitter]&.strip&.delete(".")
|
|
50
50
|
final_emitter = overriden_emitter.blank? ? original_emitter : overriden_emitter
|
|
51
|
-
|
|
51
|
+
# 'overriden_emitter' selects the emitter of the event, it is not part of what is tracked:
|
|
52
|
+
# it is dropped from the payload instead of being published as an 'overridenEmitter' key.
|
|
53
|
+
Event.new(SecureRandom.uuid, final_emitter, kind, name, deep_camelize(data.except(:overriden_emitter)))
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
def create_data_from_entity_changes(action_name, entity, request_id, request_entity_metadata, changes, user_metadata_lambda, association_columns, ignored_model_changes, flu_overriden_emitter_lambda)
|
data/lib/flu-rails/util.rb
CHANGED
|
@@ -16,12 +16,13 @@ module Flu
|
|
|
16
16
|
association_columns = entity_type.flu_association_columns
|
|
17
17
|
user_metadata_lambda = entity_type.flu_user_metadata_lambdas[:create]
|
|
18
18
|
ignored_model_changes = entity_type.flu_ignored_model_changes
|
|
19
|
+
overriden_emitter_lambda = entity_type.flu_overriden_emitter_lambda
|
|
19
20
|
|
|
20
21
|
entities.each do |entity|
|
|
21
22
|
print "\r" unless current_entity_index == 0
|
|
22
23
|
current_entity_index += 1
|
|
23
24
|
print "#{entity_type} (#{current_entity_type_index}/#{total_number_of_entity_types}) : #{current_entity_index}/#{total_number_of_entities}"
|
|
24
|
-
data = extract_data_from(entity, event_factory, user_metadata_lambda, association_columns, ignored_model_changes)
|
|
25
|
+
data = extract_data_from(entity, event_factory, user_metadata_lambda, association_columns, ignored_model_changes, overriden_emitter_lambda)
|
|
25
26
|
event = event_factory.build_entity_change_event(data)
|
|
26
27
|
event.timestamp = entity.created_at unless entity.created_at.nil?
|
|
27
28
|
event_publisher.publish(event)
|
|
@@ -52,9 +53,17 @@ module Flu
|
|
|
52
53
|
end
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
def extract_data_from(entity, event_factory, user_metadata_lambda, association_columns, ignored_model_changes)
|
|
56
|
+
def extract_data_from(entity, event_factory, user_metadata_lambda, association_columns, ignored_model_changes, overriden_emitter_lambda)
|
|
56
57
|
changes = create_changes_from_existing(entity)
|
|
57
|
-
event_factory.create_data_from_entity_changes(:create,
|
|
58
|
+
event_factory.create_data_from_entity_changes(:create,
|
|
59
|
+
entity,
|
|
60
|
+
nil,
|
|
61
|
+
nil,
|
|
62
|
+
changes,
|
|
63
|
+
user_metadata_lambda,
|
|
64
|
+
association_columns,
|
|
65
|
+
ignored_model_changes,
|
|
66
|
+
overriden_emitter_lambda)
|
|
58
67
|
end
|
|
59
68
|
|
|
60
69
|
def create_changes_from_existing(entity)
|
data/lib/flu-rails/version.rb
CHANGED
data/lib/flu-rails.rb
CHANGED
|
@@ -62,7 +62,10 @@ module Flu
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def self.is_testing_environment?
|
|
65
|
-
defined?(Rails)
|
|
65
|
+
# 'defined?(Rails)' alone is not enough: gems such as 'rails-html-sanitizer' define an empty
|
|
66
|
+
# 'Rails' namespace, so the constant can exist without railties ever defining 'Rails.env'.
|
|
67
|
+
return false unless defined?(Rails) && Rails.respond_to?(:env)
|
|
68
|
+
config.development_environments.include?(Rails.env)
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
def self.extend_models_and_controllers
|
metadata
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flu-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0.
|
|
4
|
+
version: 8.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Loïc Vigneron
|
|
8
8
|
- Lorent Lempereur
|
|
9
9
|
- Thibault Poncelet
|
|
10
|
+
- Logan Clément
|
|
10
11
|
bindir: bin
|
|
11
12
|
cert_chain: []
|
|
12
13
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -169,8 +170,7 @@ description: Seamlessly emit events from an existing Rails application, without
|
|
|
169
170
|
its codebase, and publish them to RabbitMQ. Events are generated from CRUD operations
|
|
170
171
|
on ActiveRecord models and from requests on Rails controller actions.
|
|
171
172
|
email:
|
|
172
|
-
-
|
|
173
|
-
- info@commuty.net
|
|
173
|
+
- support@commuty.net
|
|
174
174
|
executables: []
|
|
175
175
|
extensions: []
|
|
176
176
|
extra_rdoc_files: []
|
|
@@ -178,6 +178,7 @@ files:
|
|
|
178
178
|
- CHANGELOG.md
|
|
179
179
|
- MIT-LICENSE
|
|
180
180
|
- README.md
|
|
181
|
+
- flu-rails.gemspec
|
|
181
182
|
- lib/flu-rails.rb
|
|
182
183
|
- lib/flu-rails/action_controller_extender.rb
|
|
183
184
|
- lib/flu-rails/active_record_extender.rb
|
|
@@ -195,9 +196,8 @@ homepage: https://github.com/crepesourcing/flu-rails
|
|
|
195
196
|
licenses:
|
|
196
197
|
- MIT
|
|
197
198
|
metadata:
|
|
198
|
-
homepage_uri: https://github.com/crepesourcing/flu-rails
|
|
199
199
|
source_code_uri: https://github.com/crepesourcing/flu-rails
|
|
200
|
-
changelog_uri: https://github.com/crepesourcing/flu-rails/blob/
|
|
200
|
+
changelog_uri: https://github.com/crepesourcing/flu-rails/blob/main/CHANGELOG.md
|
|
201
201
|
bug_tracker_uri: https://github.com/crepesourcing/flu-rails/issues
|
|
202
202
|
rubygems_mfa_required: 'true'
|
|
203
203
|
rdoc_options: []
|