flu-rails 1.2.0 → 8.0.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: 95ccc91aa5396a70d42d46300b5d7fc48321a3c3d3bea32e77d88b0b4a542e35
4
- data.tar.gz: e71784f540b50b412469fb10af164b30942d29190fe2a9e9d7b0725a41b713bd
3
+ metadata.gz: 721522defefd5f7c30f0cd24dd1773b6191cf93bc8162d791e349883dd91698f
4
+ data.tar.gz: 3d5e0c52ddbffbdf5c021647a76460acde5726ca1201bda1022d21fdb3095a05
5
5
  SHA512:
6
- metadata.gz: e85087d058f0ce9e3cb32c7e7a3dc97471f158b9c973f491a66ccdb33f47f84c78cc78a364a16b3345dd0f036e57a1c686495c57ae2eb60e7decdb153c2a0e9f
7
- data.tar.gz: a15ad5ed11e2c3a2a3cade60e643b4b21b5583196d3c52429b2ae09fdec8445f7ab282f013899218add3c95af4b9a655331fe8a24b9565ab408d969cc8e5fffb
6
+ metadata.gz: 9965aef8635a94a1f2e8843253e3c8817b2b6b0f61f13b1f0137a1d555eb638c6e12d4f620c004e47f3365cec9fc9da57a2076e629f53ea11df045c21a0c0a27
7
+ data.tar.gz: 5818a4c90e2b819a12483f9683a75119c33e6573b57e0952916a3cbd258dd6d0e536be85105efbb1b1415fafa105c5de9de478ae3976a06f12ab2f28a86203a8
data/CHANGELOG.md CHANGED
@@ -5,6 +5,66 @@ 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
+ ### [Unreleased]
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
35
+
36
+ **Fixed**
37
+
38
+ * Fix tracking a controller request raising `ActionController::UnfilteredParameters`. Controller params
39
+ reach `EventFactory` as unpermitted `ActionController::Parameters`, on which `to_h` raises
40
+ (Rails >= 5.1). The unsafe hash is now used, which is what a read-only tracker needs. This broke
41
+ `track_requests` entirely, and went unnoticed because its specs are disabled (`xit`).
42
+ * Fix `Flu.init` raising `configuration.application_name must not be nil` on a stock Rails application.
43
+
44
+ **Changed**
45
+
46
+ * **Breaking**: `flu-rails` now supports Rails 8 exclusively.
47
+ * Drop the pre-Rails-8 compatibility shims that this makes dead code:
48
+ * `flu_changes_depending_on_active_record_version`
49
+ * the `Zeitwerk::Loader.eager_load_all` fallback in `Util::ExportService`
50
+ * Restore `activesupport` as a runtime dependency
51
+ * Require the ActiveSupport core extensions that are actually used
52
+
53
+ **Publishing**
54
+
55
+ * Add a `Rakefile` (`bundler/gem_tasks` + an `rspec` task), so that `rake release` builds, tags and publishes the gem. `rake` becomes a development dependency.
56
+ * Add `.github/workflows/release.yml`: pushing a `v*` tag checks that the tag matches `Flu::VERSION`,
57
+ runs the specs, then builds and pushes the gem through RubyGems' Trusted Publishing. No RubyGems
58
+ API key is stored in the repository — a short-lived GitHub OIDC token is exchanged for a scoped
59
+ RubyGems credential.
60
+
61
+ **Verified**
62
+
63
+ * Verified against Rails 8.1 on a real application: railtie boot, `ActiveRecord` and
64
+ `ActionController::Base`/`API` tracking through the full Rack stack, request id propagation from a
65
+ controller into its entity-change events, uploaded file mapping and user-agent rejection — with
66
+ every framework deprecator set to `:raise`. No deprecation is triggered.
67
+
8
68
  ### [1.2.0] - 2026-07-31
9
69
 
10
70
  * Declare `required_ruby_version` as `>= 3.2`
data/MIT-LICENSE CHANGED
@@ -1,20 +1,21 @@
1
- Copyright 2018
1
+ MIT License
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
3
+ Copyright (c) 2026 Commuty SA
10
4
 
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
13
11
 
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -16,7 +16,7 @@ For now, events are generated from:
16
16
  Add the gem to your project's Gemfile:
17
17
 
18
18
  ```ruby
19
- gem "flu-rails", git: "https://github.com/crepesourcing/flu-rails.git"
19
+ gem "flu-rails"
20
20
  ```
21
21
 
22
22
  Then, create an initializer into your Rails app (`config/initializers/flu-rails.rb`)
@@ -38,20 +38,18 @@ Each configuration is detailed below.
38
38
  ## Requirements
39
39
 
40
40
  * Ruby >= 3.2 (tested against 3.2, 3.3 and 3.4)
41
- * Tested with Rails 8 (`activerecord` and `actionpack`)
42
- * Tested with RabbitMQ 3.5.8
41
+ * Rails 8 only (`activerecord`, `actionpack` and `activesupport` are runtime dependencies,
42
+ constrained to `~> 8.0`). `flu-rails` extends `ActiveRecord::Base` and `ActionController::Base`, so it requires Rails.
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).
43
46
 
44
47
  ## Usage
45
48
 
46
49
  ### Start up
47
50
 
48
- If your application does not include `Railties`, `flu-rails` can be started as followed:
49
- ```
50
- Flu.init
51
- Flu.start
52
- ```
53
-
54
- `flu-rails` startup waits until its RabbitMQ exchange is connected.
51
+ `flu-rails` starts automatically through its `Railtie`: there is nothing to call by hand.
52
+ Its startup waits until its RabbitMQ exchange is connected.
55
53
 
56
54
  ### Track changes on an ActiveRecord model
57
55
 
@@ -90,7 +88,7 @@ For instance:
90
88
 
91
89
  ### Track requests to a Rails Controller action
92
90
 
93
- All subclasses of `ActionController::Base` or `ActionController::API` (Rails 5) that call `track_requests` are "tracked". _E.g._:
91
+ All subclasses of `ActionController::Base` or `ActionController::API` that call `track_requests` are "tracked". _E.g._:
94
92
 
95
93
  ```ruby
96
94
  class ApplicationController < ActionController::Base
@@ -167,7 +165,7 @@ All options have a default value. However, all of them can be changed in your in
167
165
  | `auto_connect_to_exchange` | `true`| Boolean | Optional | Thanks to `Railties`, `flu-rails` starts automatically when the Rails app boots. However, this can be useful to not connect RabbitMQ at start up. To do so, set `auto_connect_to_exchange` to `false`. | `false` |
168
166
  | `default_ignored_model_changes` | `[:password, :password_confirmation, :created_at, :updated_at]` | Boolean | Optional | By default, all these attributes will be ignored from model changes when creating an event. For instance, this means that timestamp fields (`created_at` and `updated_at`) are not monitored when they change. | `[]` |
169
167
  | `default_ignored_request_params` | `[:password, :password_confirmation, :controller, :action]` | Boolean | Optional | By default, all these parameters will be ignored from controller request's `params` when creating an event. | `false` |
170
- | `application_name` | `Rails.application.class.parent_name.to_s.camelize` | String | Required | Is used as `emitter` for each event created by `flu-rails`, if not overriden by the `track_met`. | `my_app` |
168
+ | `application_name` | `Rails.application.class.module_parent_name`, resolved on startup | String | Required | Is used as `emitter` for each event created by `flu-rails`, if not overriden by the `track_met`. | `my_app` |
171
169
  | `bunny_options` | `{}` | Hash of symbols | Optional | Additional options to add when connecting the RabbitMQ broker. This overrides the existing options with the same name. | `{ verify_peer: true }` |
172
170
 
173
171
  ## How to execute tests
@@ -175,10 +173,32 @@ All options have a default value. However, all of them can be changed in your in
175
173
  From the `flu-rails` directory:
176
174
 
177
175
  ```
178
- $ docker build . -t flu:test
179
- $ docker run -v `pwd`:/usr/src/app/ flu:test rspec spec
176
+ $ docker compose run --rm specs
180
177
  ```
181
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
+
182
202
  ## Example of Events
183
203
 
184
204
  ### Structure of an Active Record change
@@ -270,3 +290,23 @@ For instance, calling the action `destroy` of `CountryController` will emit this
270
290
  ## Side-notes
271
291
 
272
292
  * `assocations` node contains `belongs_to` associations only.
293
+
294
+
295
+ ## How to release a new version
296
+
297
+ Releases are published to [RubyGems](https://rubygems.org/gems/flu-rails) by GitHub Actions
298
+ (`.github/workflows/release.yml`), through [Trusted Publishing](https://guides.rubygems.org/trusted-publishing/):
299
+ no API key is stored in this repository, the workflow exchanges a short-lived GitHub OIDC token for a
300
+ scoped RubyGems credential.
301
+
302
+ 1. Update `Flu::VERSION` in `lib/flu-rails/version.rb` and the `CHANGELOG.md`
303
+ 2. Commit and push these changes to `main`
304
+ 3. Tag the commit and push the tag:
305
+
306
+ ```
307
+ $ git tag -a v8.0.1 -m "Version 8.0.1"
308
+ $ git push origin v8.0.1
309
+ ```
310
+
311
+ The workflow then checks that the tag matches `Flu::VERSION`, runs the tests, builds the gem
312
+ and pushes it. It only publishes tags starting with `v`.
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
@@ -1,3 +1,6 @@
1
+ require "active_support/core_ext/string/inflections"
2
+ require "active_support/core_ext/time/zones"
3
+
1
4
  module Flu
2
5
  class ActionControllerExtender
3
6
  def self.extend_controllers(event_factory, event_publisher, logger)
@@ -18,49 +21,38 @@ module Flu
18
21
  ignored_request_params = options.fetch(:ignored_request_params, []).map(&:to_sym)
19
22
  emitter_lambda = options[:emitter]
20
23
 
21
- before_action do
22
- define_request_id
23
- @request_start_time = Time.zone.now
24
- end
25
- prepend_before_action do
26
- define_request_entity_metadata_lambda(entity_metadata_lambda)
27
- end
28
- prepend_after_action do
29
- track_requests(event_factory, event_publisher, user_metadata_lambda, ignored_request_params, emitter_lambda)
30
- remove_request_entity_metadata_lambda
31
- end
32
- after_action do
33
- remove_request_id
34
- end
35
-
36
- 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
37
31
  request_id = SecureRandom.uuid
38
32
  @flu_request_id = request_id
39
33
  Flu::CoreExt.flu_tracker_request_id = request_id
40
34
  end
41
35
 
42
- def remove_request_id
36
+ define_method(:flu_remove_request_id) do
43
37
  Flu::CoreExt.flu_tracker_request_id = nil
44
38
  end
45
39
 
46
- def define_request_entity_metadata_lambda(entity_metadata_lambda)
40
+ define_method(:flu_define_request_entity_metadata) do
47
41
  Flu::CoreExt.flu_tracker_request_entity_metadata = instance_exec(&entity_metadata_lambda) if entity_metadata_lambda
48
42
  end
49
43
 
50
- def remove_request_entity_metadata_lambda
44
+ define_method(:flu_remove_request_entity_metadata) do
51
45
  Flu::CoreExt.flu_tracker_request_entity_metadata = nil
52
46
  end
53
47
 
54
- def rejected_origin?(request)
55
- rejected_user_agents = Regexp.union(Flu.config.rejected_user_agents)
56
- user_agent = request.user_agent
57
- matching_user_agents = user_agent&.match(rejected_user_agents)
58
- !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?
59
51
  end
60
52
 
61
- def track_requests(event_factory, event_publisher, user_metadata_lambda, ignored_request_params, emitter_lambda)
62
- if rejected_origin?(request)
63
- logger.warn "Origin user agent rejected: #{request.user_agent}"
53
+ define_method(:flu_track_request) do
54
+ if flu_rejected_origin?
55
+ logger.warn("Origin user agent rejected: #{request.user_agent}")
64
56
  else
65
57
  tracked_request = event_factory.create_data_from_request(@flu_request_id,
66
58
  params,
@@ -74,6 +66,21 @@ module Flu
74
66
  event_publisher.publish(event)
75
67
  end
76
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
77
84
  end
78
85
  end
79
86
  end
@@ -1,3 +1,5 @@
1
+ require "active_support/core_ext/object/try"
2
+
1
3
  module Flu
2
4
  class ActiveRecordExtender
3
5
  def self.extend_models(event_factory, event_publisher)
@@ -8,8 +10,8 @@ module Flu
8
10
  self.flu_ignored_model_changes = options.fetch(:ignored_model_changes, []).map(&:to_s)
9
11
  self.flu_overriden_emitter_lambda = options.fetch(:emitter, nil)
10
12
 
11
- after_create { flu_track_entity_change(:create, flu_changes_depending_on_active_record_version, event_factory) }
12
- after_update { flu_track_entity_change(:update, flu_changes_depending_on_active_record_version, event_factory) }
13
+ after_create { flu_track_entity_change(:create, saved_changes, event_factory) }
14
+ after_update { flu_track_entity_change(:update, saved_changes, event_factory) }
13
15
  after_destroy { flu_track_entity_change(:destroy, { "id" => [id, nil] }, event_factory) }
14
16
  after_commit { flu_commit_changes(event_factory, event_publisher) }
15
17
  after_rollback { flu_rollback_changes }
@@ -55,10 +57,6 @@ module Flu
55
57
  end
56
58
  end
57
59
 
58
- def flu_changes_depending_on_active_record_version
59
- respond_to?(:saved_changes) ? saved_changes : changes
60
- end
61
-
62
60
  def flu_changes
63
61
  @flu_changes ||= []
64
62
  end
@@ -1,4 +1,7 @@
1
1
  require "securerandom"
2
+ require "active_support/core_ext/object/blank"
3
+ require "active_support/core_ext/string/inflections"
4
+ require "active_support/core_ext/time/zones"
2
5
  require_relative "event"
3
6
 
4
7
  module Flu
@@ -45,7 +48,9 @@ module Flu
45
48
  original_emitter = @emitter
46
49
  overriden_emitter = data[:overriden_emitter]&.strip&.delete(".")
47
50
  final_emitter = overriden_emitter.blank? ? original_emitter : overriden_emitter
48
- Event.new(SecureRandom.uuid, final_emitter, kind, name, deep_camelize(data))
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)))
49
54
  end
50
55
 
51
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)
@@ -71,12 +76,17 @@ module Flu
71
76
  response_code: response.status,
72
77
  user_agent: request.user_agent,
73
78
  duration: Time.zone.now - request_start_time,
74
- params: params.except(*ignored_request_params).except(*@default_ignored_request_params).to_h
79
+ params: extract_params(params, ignored_request_params)
75
80
  }
76
81
  end
77
82
 
78
83
  private
79
84
 
85
+ def extract_params(params, ignored_request_params)
86
+ remaining = params.except(*ignored_request_params).except(*@default_ignored_request_params)
87
+ remaining.respond_to?(:to_unsafe_h) ? remaining.to_unsafe_h.to_h : remaining.to_h
88
+ end
89
+
80
90
  def deep_camelize(value)
81
91
  case value
82
92
  when Array
@@ -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)
@@ -42,8 +43,7 @@ module Flu
42
43
  end
43
44
 
44
45
  def find_all_entity_types
45
- eager_loaded = Rails.application.eager_load!
46
- Zeitwerk::Loader.eager_load_all if !eager_loaded && defined?(Zeitwerk)
46
+ Rails.application.eager_load!
47
47
  ActiveRecord::Base.descendants
48
48
  end
49
49
 
@@ -53,9 +53,17 @@ module Flu
53
53
  end
54
54
  end
55
55
 
56
- 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)
57
57
  changes = create_changes_from_existing(entity)
58
- event_factory.create_data_from_entity_changes(:create, entity, nil, nil, changes, user_metadata_lambda, association_columns, ignored_model_changes, nil)
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)
59
67
  end
60
68
 
61
69
  def create_changes_from_existing(entity)
@@ -1,3 +1,3 @@
1
1
  module Flu
2
- VERSION = "1.2.0"
2
+ VERSION = "8.0.1"
3
3
  end
data/lib/flu-rails.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "logger"
2
2
  require "json"
3
+ require "active_support/core_ext/module/introspection"
3
4
  require_relative "flu-rails/version"
4
5
  require_relative "flu-rails/event"
5
6
  require_relative "flu-rails/event_factory"
@@ -33,6 +34,7 @@ module Flu
33
34
  end
34
35
 
35
36
  def self.init
37
+ @configuration.application_name ||= default_application_name
36
38
  raise "configuration.application_name must not be nil" if @configuration.application_name.nil?
37
39
  @logger = @configuration.logger
38
40
  @event_factory = Flu::EventFactory.new(@configuration)
@@ -40,6 +42,15 @@ module Flu
40
42
  extend_models_and_controllers
41
43
  end
42
44
 
45
+ def self.default_application_name
46
+ if defined?(Rails) && Rails.respond_to?(:application)
47
+ application = Rails.application
48
+ application.nil? ? nil : application.class.module_parent_name
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
43
54
  def self.create_event_publisher(configuration)
44
55
  if is_testing_environment?
45
56
  logger.info("Loading Flu with a dummy event publisher (this will not connect any exchange)")
@@ -51,7 +62,10 @@ module Flu
51
62
  end
52
63
 
53
64
  def self.is_testing_environment?
54
- defined?(Rails) && config.development_environments.include?(Rails.env)
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)
55
69
  end
56
70
 
57
71
  def self.extend_models_and_controllers
@@ -79,7 +93,7 @@ module Flu
79
93
  config.auto_connect_to_exchange = true
80
94
  config.default_ignored_model_changes = [:password, :password_confirmation, :created_at, :updated_at]
81
95
  config.default_ignored_request_params = [:password, :password_confirmation, :controller, :action]
82
- config.application_name = defined?(Rails) ? Rails.application.class.module_parent_name : nil
96
+ config.application_name = nil
83
97
  config.bunny_options = {}
84
98
  end
85
99
  end
metadata CHANGED
@@ -1,86 +1,101 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flu-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 8.0.1
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
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
- name: bunny
16
+ name: actionpack
16
17
  requirement: !ruby/object:Gem::Requirement
17
18
  requirements:
18
19
  - - "~>"
19
20
  - !ruby/object:Gem::Version
20
- version: '3.1'
21
+ version: '8.0'
21
22
  type: :runtime
22
23
  prerelease: false
23
24
  version_requirements: !ruby/object:Gem::Requirement
24
25
  requirements:
25
26
  - - "~>"
26
27
  - !ruby/object:Gem::Version
27
- version: '3.1'
28
+ version: '8.0'
28
29
  - !ruby/object:Gem::Dependency
29
- name: logger
30
+ name: activerecord
30
31
  requirement: !ruby/object:Gem::Requirement
31
32
  requirements:
32
33
  - - "~>"
33
34
  - !ruby/object:Gem::Version
34
- version: '1.7'
35
+ version: '8.0'
35
36
  type: :runtime
36
37
  prerelease: false
37
38
  version_requirements: !ruby/object:Gem::Requirement
38
39
  requirements:
39
40
  - - "~>"
40
41
  - !ruby/object:Gem::Version
41
- version: '1.7'
42
+ version: '8.0'
42
43
  - !ruby/object:Gem::Dependency
43
- name: rabbitmq_http_api_client
44
+ name: activesupport
44
45
  requirement: !ruby/object:Gem::Requirement
45
46
  requirements:
46
47
  - - "~>"
47
48
  - !ruby/object:Gem::Version
48
- version: '3.2'
49
+ version: '8.0'
49
50
  type: :runtime
50
51
  prerelease: false
51
52
  version_requirements: !ruby/object:Gem::Requirement
52
53
  requirements:
53
54
  - - "~>"
54
55
  - !ruby/object:Gem::Version
55
- version: '3.2'
56
+ version: '8.0'
56
57
  - !ruby/object:Gem::Dependency
57
- name: actionpack
58
+ name: bunny
58
59
  requirement: !ruby/object:Gem::Requirement
59
60
  requirements:
60
61
  - - "~>"
61
62
  - !ruby/object:Gem::Version
62
- version: '8.0'
63
- type: :development
63
+ version: '3.1'
64
+ type: :runtime
64
65
  prerelease: false
65
66
  version_requirements: !ruby/object:Gem::Requirement
66
67
  requirements:
67
68
  - - "~>"
68
69
  - !ruby/object:Gem::Version
69
- version: '8.0'
70
+ version: '3.1'
70
71
  - !ruby/object:Gem::Dependency
71
- name: activerecord
72
+ name: logger
72
73
  requirement: !ruby/object:Gem::Requirement
73
74
  requirements:
74
75
  - - "~>"
75
76
  - !ruby/object:Gem::Version
76
- version: '8.0'
77
- type: :development
77
+ version: '1.7'
78
+ type: :runtime
78
79
  prerelease: false
79
80
  version_requirements: !ruby/object:Gem::Requirement
80
81
  requirements:
81
82
  - - "~>"
82
83
  - !ruby/object:Gem::Version
83
- version: '8.0'
84
+ version: '1.7'
85
+ - !ruby/object:Gem::Dependency
86
+ name: rabbitmq_http_api_client
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '3.2'
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: '3.2'
84
99
  - !ruby/object:Gem::Dependency
85
100
  name: byebug
86
101
  requirement: !ruby/object:Gem::Requirement
@@ -109,6 +124,20 @@ dependencies:
109
124
  - - "~>"
110
125
  - !ruby/object:Gem::Version
111
126
  version: '0.6'
127
+ - !ruby/object:Gem::Dependency
128
+ name: rake
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '13.0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '13.0'
112
141
  - !ruby/object:Gem::Dependency
113
142
  name: rspec
114
143
  requirement: !ruby/object:Gem::Requirement
@@ -141,8 +170,7 @@ description: Seamlessly emit events from an existing Rails application, without
141
170
  its codebase, and publish them to RabbitMQ. Events are generated from CRUD operations
142
171
  on ActiveRecord models and from requests on Rails controller actions.
143
172
  email:
144
- - info@spin42.com
145
- - info@commuty.net
173
+ - support@commuty.net
146
174
  executables: []
147
175
  extensions: []
148
176
  extra_rdoc_files: []
@@ -150,6 +178,7 @@ files:
150
178
  - CHANGELOG.md
151
179
  - MIT-LICENSE
152
180
  - README.md
181
+ - flu-rails.gemspec
153
182
  - lib/flu-rails.rb
154
183
  - lib/flu-rails/action_controller_extender.rb
155
184
  - lib/flu-rails/active_record_extender.rb
@@ -167,9 +196,8 @@ homepage: https://github.com/crepesourcing/flu-rails
167
196
  licenses:
168
197
  - MIT
169
198
  metadata:
170
- homepage_uri: https://github.com/crepesourcing/flu-rails
171
199
  source_code_uri: https://github.com/crepesourcing/flu-rails
172
- changelog_uri: https://github.com/crepesourcing/flu-rails/blob/master/CHANGELOG.md
200
+ changelog_uri: https://github.com/crepesourcing/flu-rails/blob/main/CHANGELOG.md
173
201
  bug_tracker_uri: https://github.com/crepesourcing/flu-rails/issues
174
202
  rubygems_mfa_required: 'true'
175
203
  rdoc_options: []
@@ -186,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
214
  - !ruby/object:Gem::Version
187
215
  version: '0'
188
216
  requirements: []
189
- rubygems_version: 4.0.17
217
+ rubygems_version: 3.6.9
190
218
  specification_version: 4
191
219
  summary: Track your application events and publish them to RabbitMQ.
192
220
  test_files: []