pub_sub_model_sync 0.5.0.1 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f08249ef28730afdc2a0f3b025ef66d5117694fdc4ed995e9eb907e37e60defb
4
- data.tar.gz: cc8d337de6952db6e9747912178ce7fd09f93c3a600d1d4756671fb6bcefadad
3
+ metadata.gz: 57e8d23c9e514734a8a45664f641378bbb46e8de5315c536a0f692efcbe29dd2
4
+ data.tar.gz: d0f290dac2b0563ffe5412f85e1a6a6e340e281049755b26dc732a3661501b92
5
5
  SHA512:
6
- metadata.gz: cdca1e7397fa5fae46198fce8ae24036318d619d53cff5c06e8e8c266423a5681e48588eddcced3271747242a35fc77b1c75bf567d5461c4fa7f573ae29c4c15
7
- data.tar.gz: 0c48d83f3904c5872cdc3b48f2d341be84cbe84899a3fdc0738c9ad290e5e6c1c49ca2ab226e12df4f097d6f927e603b4691f64760a8d4dd9c703431711e71ec
6
+ metadata.gz: 351901f98e6c806e7a4efe20abdac65de5bf8f716dc57e1889302eab02d33b3f2f4d449cd0d351fd5ae882d16abe79a77791bea8ad956c52cda47829319eb858
7
+ data.tar.gz: e906d601a8c37b999a8b6d550e605e9c04b67db692cec4b60220ae286bef9adde7132d8614cee4ca7dab9ef43538ae2baede3f07e402c4c21a189b79a9ba6873
@@ -1,5 +1,27 @@
1
1
  # Change Log
2
2
 
3
+ # 0.5.4 (January 8, 2021)
4
+ - fix: exclude identifiers when syncing model
5
+ - feat: callbacks support for future extra params
6
+ - feat: make connectors configurable
7
+ - feat: add :process! and :process, :publish!, :publish methods to payload
8
+ - feat: auto retry 2 times when "could not obtain a database connection within 5.000 seconds..." error occurs
9
+
10
+ # 0.5.3 (December 30, 2020)
11
+ - fix: kafka consume all messages from different apps
12
+ - style: use the correct consumer key
13
+
14
+ # 0.5.2 (December 30, 2020)
15
+ - fix: rabbitmq deliver messages to all subscribers
16
+ - fix: rabbitmq persist messages to recover after restarting
17
+
18
+ # 0.5.1.1 (December 29, 2020)
19
+ - Hotfix: auto convert class name into string
20
+
21
+ # 0.5.1 (December 24, 2020)
22
+ - feat: rename publisher callbacks to be more understandable
23
+ - feat: add callbacks to listen when processing a message (before saving sync)
24
+
3
25
  # 0.5.0.1 (December 22, 2020)
4
26
  - fix: add missing rabbit mock method
5
27
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pub_sub_model_sync (0.5.0.1)
4
+ pub_sub_model_sync (0.5.4)
5
5
  rails
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -28,10 +28,9 @@ And then execute: $ bundle install
28
28
  ```ruby
29
29
  # initializers/pub_sub_config.rb
30
30
  PubSubModelSync::Config.service_name = :google
31
- PubSubModelSync::Config.project = 'project-id'
31
+ PubSubModelSync::Config.project = 'google-project-id'
32
32
  PubSubModelSync::Config.credentials = 'path-to-the-config'
33
33
  PubSubModelSync::Config.topic_name = 'sample-topic'
34
- PubSubModelSync::Config.subscription_name = 'p1-subscriber'
35
34
  ```
36
35
  See details here:
37
36
  https://github.com/googleapis/google-cloud-ruby/tree/master/google-cloud-pubsub
@@ -40,7 +39,7 @@ And then execute: $ bundle install
40
39
  ```ruby
41
40
  PubSubModelSync::Config.service_name = :rabbitmq
42
41
  PubSubModelSync::Config.bunny_connection = 'amqp://guest:guest@localhost'
43
- PubSubModelSync::Config.queue_name = ''
42
+ PubSubModelSync::Config.queue_name = 'model-sync'
44
43
  PubSubModelSync::Config.topic_name = 'sample-topic'
45
44
  ```
46
45
  See details here: https://github.com/ruby-amqp/bunny
@@ -48,7 +47,7 @@ And then execute: $ bundle install
48
47
  - configuration for Apache Kafka (You need kafka installed)
49
48
  ```ruby
50
49
  PubSubModelSync::Config.service_name = :kafka
51
- PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "localhost:2121"], logger: Rails.logger]
50
+ PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "localhost:2121"], { logger: Rails.logger }]
52
51
  PubSubModelSync::Config.topic_name = 'sample-topic'
53
52
  ```
54
53
  See details here: https://github.com/zendesk/ruby-kafka
@@ -59,7 +58,13 @@ And then execute: $ bundle install
59
58
  ```ruby
60
59
  rake pub_sub_model_sync:start
61
60
  ```
62
- Note: Publishers do not need todo this
61
+ Note: Publishers do not need todo this
62
+ Note2 (Rails 6+): Due to Zeitwerk, you need to load listeners manually when syncing outside ```rake pub_sub_model_sync:start```
63
+ ```ruby
64
+ # PubSubModelSync::Config.subscribers ==> []
65
+ Rails.application.try(:eager_load!)
66
+ # PubSubModelSync::Config.subscribers ==> [#<PubSubModelSync::Subscriber:0x000.. @klass="Article", @action=:create..., ....]
67
+ ```
63
68
 
64
69
  - Check the service status with:
65
70
  ```PubSubModelSync::MessagePublisher.publish_data('Test message', {sample_value: 10}, :create)```
@@ -163,6 +168,9 @@ Note: Be careful with collision of names
163
168
  ```.ps_subscriber_changed?(data)```
164
169
  By default: ```model.changed?```
165
170
 
171
+ - Permit to perform custom actions before saving sync of the model (:cancel can be returned to skip sync)
172
+ ```.ps_before_save_sync(payload)```
173
+
166
174
  ### Publishers
167
175
  - Permit to configure crud publishers
168
176
  ```ps_publish(attrs, actions: nil, as_klass: nil)```
@@ -198,10 +206,13 @@ Note: Be careful with collision of names
198
206
  * action_name: (required, :sim) Action name
199
207
  * as_klass: (optional, :string) Custom class name (Default current model name)
200
208
 
201
- - Publish a class level notification (Same as above: manual call)
209
+ - Payload actions
202
210
  ```ruby
203
211
  payload = PubSubModelSync::Payload.new({ title: 'hello' }, { action: :greeting, klass: 'User' })
204
- payload.publish!
212
+ payload.publish! # publishes notification data. It raises exception if fails and does not call ```:on_error_publishing``` callback
213
+ payload.publish # publishes notification data. On error does not raise exception but calls ```:on_error_publishing``` callback
214
+ payload.process! # process a notification data. It raises exception if fails and does not call ```.on_error_processing``` callback
215
+ payload.publish # process a notification data. It does not raise exception if fails but calls ```.on_error_processing``` callback
205
216
  ```
206
217
 
207
218
  - Get crud publisher configured for the class
@@ -274,22 +285,26 @@ config = PubSubModelSync::Config
274
285
  config.debug = true
275
286
  ```
276
287
 
277
- - ```debug = true```
288
+ - ```.subscription_name = 'app-2'```
289
+ Permit to define a custom consumer identifier (Default: Rails application name)
290
+ - ```.debug = true```
278
291
  (true/false*) => show advanced log messages
279
- - ```logger = Rails.logger```
292
+ - ```.logger = Rails.logger```
280
293
  (Logger) => define custom logger
281
- - ```disabled = true```
282
- (true/false*) => if true, does not publish model messages (Create/Update/Destroy)
283
- - ```on_process_success = ->(payload, subscriber) { puts payload }```
294
+ - ```.disabled_callback_publisher = ->(_model, _action) { false }```
295
+ (true/false*) => if true, does not listen model callbacks for auto sync (Create/Update/Destroy)
296
+ - ```.on_before_processing = ->(payload, {subscriber:}) { puts payload }```
297
+ (Proc) => called before processing received message (:cancel can be returned to skip processing)
298
+ - ```.on_success_processing = ->(payload, {subscriber:}) { puts payload }```
284
299
  (Proc) => called when a message was successfully processed
285
- - ```on_process_error = ->(exception, payload) { sleep 1; payload.process! }```
286
- (Proc) => called when a message failed when processing
287
- - ```on_before_publish = ->(payload) { puts payload }```
288
- (Proc) => called before publishing a message
289
- - ```on_after_publish = ->(payload) { puts payload }```
300
+ - ```.on_error_processing = ->(exception, {payload:, subscriber:}) { payload.delay(...).process! }```
301
+ (Proc) => called when a message failed when processing (delayed_job or similar can be used for retrying)
302
+ - ```.on_before_publish = ->(payload) { puts payload }```
303
+ (Proc) => called before publishing a message (:cancel can be returned to skip publishing)
304
+ - ```.on_after_publish = ->(payload) { puts payload }```
290
305
  (Proc) => called after publishing a message
291
- - ```on_publish_error = ->(exception, payload) { sleep 1; payload.publish! }```
292
- (Proc) => called when failed publishing a message
306
+ - ```.on_error_publish = ->(exception, {payload:}) { payload.delay(...).publish! }```
307
+ (Proc) => called when failed publishing a message (delayed_job or similar can be used for retrying)
293
308
 
294
309
  ## TODO
295
310
  - Add alias attributes when subscribing (similar to publisher)
@@ -13,5 +13,12 @@ module PubSubModelSync
13
13
  config.log message, kind
14
14
  end
15
15
  end
16
+
17
+ def retry_error(error_klass, qty: 2, &block)
18
+ @retries ||= 0
19
+ block.call
20
+ rescue error_klass => _e
21
+ (@retries += 1) <= qty ? retry : raise
22
+ end
16
23
  end
17
24
  end
@@ -10,12 +10,13 @@ module PubSubModelSync
10
10
  cattr_accessor(:debug) { false }
11
11
  cattr_accessor :logger # LoggerInst
12
12
 
13
- cattr_accessor(:on_process_success) { ->(_payload, _subscriber) {} }
14
- cattr_accessor(:on_process_error) { ->(_exception, _payload) {} }
15
- cattr_accessor(:on_before_publish) { ->(_payload) {} }
13
+ cattr_accessor(:on_before_processing) { ->(_payload, _info) {} } # return :cancel to skip
14
+ cattr_accessor(:on_success_processing) { ->(_payload, _info) {} }
15
+ cattr_accessor(:on_error_processing) { ->(_exception, _info) {} }
16
+ cattr_accessor(:on_before_publish) { ->(_payload) {} } # return :cancel to skip
16
17
  cattr_accessor(:on_after_publish) { ->(_payload) {} }
17
- cattr_accessor(:on_publish_error) { ->(_exception, _payload) {} }
18
- cattr_accessor(:disabled) { false }
18
+ cattr_accessor(:on_error_publish) { ->(_exception, _info) {} }
19
+ cattr_accessor(:disabled_callback_publisher) { ->(_model, _action) { false } }
19
20
 
20
21
  # google service
21
22
  cattr_accessor :project, :credentials, :topic_name, :subscription_name
@@ -2,7 +2,7 @@
2
2
 
3
3
  module PubSubModelSync
4
4
  class MessageProcessor < PubSubModelSync::Base
5
- attr_accessor :payload
5
+ attr_accessor :payload, :raise_error
6
6
 
7
7
  # @param payload (Payload): payload to be delivered
8
8
  # @Deprecated: def initialize(data, klass, action)
@@ -22,17 +22,27 @@ module PubSubModelSync
22
22
  private
23
23
 
24
24
  def run_subscriber(subscriber)
25
- subscriber.eval_message(payload.data)
26
- config.on_process_success.call(payload, subscriber)
27
- log "processed message with: #{payload}"
25
+ return unless processable?(subscriber)
26
+
27
+ retry_error(ActiveRecord::ConnectionTimeoutError, qty: 2) do
28
+ subscriber.process!(payload)
29
+ res = config.on_success_processing.call(payload, { subscriber: subscriber })
30
+ log "processed message with: #{payload.inspect}" if res != :skip_log
31
+ end
28
32
  rescue => e
29
- print_subscriber_error(e)
33
+ raise_error ? raise : print_subscriber_error(e, subscriber)
34
+ end
35
+
36
+ def processable?(subscriber)
37
+ cancel = config.on_before_processing.call(payload, { subscriber: subscriber }) == :cancel
38
+ log("process message cancelled: #{payload}") if cancel && config.debug
39
+ !cancel
30
40
  end
31
41
 
32
42
  # @param error (Error)
33
- def print_subscriber_error(error)
43
+ def print_subscriber_error(error, subscriber)
34
44
  info = [payload, error.message, error.backtrace]
35
- res = config.on_process_error.call(error, payload)
45
+ res = config.on_error_processing.call(error, { payload: payload, subscriber: subscriber })
36
46
  log("Error processing message: #{info}", :error) if res != :skip_log
37
47
  end
38
48
 
@@ -8,7 +8,7 @@ module PubSubModelSync
8
8
  end
9
9
 
10
10
  def publish_data(klass, data, action)
11
- payload = PubSubModelSync::Payload.new(data, { klass: klass, action: action.to_sym })
11
+ payload = PubSubModelSync::Payload.new(data, { klass: klass.to_s, action: action.to_sym })
12
12
  publish(payload)
13
13
  end
14
14
 
@@ -19,8 +19,7 @@ module PubSubModelSync
19
19
  return if model.ps_skip_sync?(action)
20
20
 
21
21
  publisher ||= model.class.ps_publisher(action)
22
- payload_info = publisher.payload(model, action)
23
- payload = PubSubModelSync::Payload.new(payload_info[:data], payload_info[:attrs])
22
+ payload = publisher.payload(model, action)
24
23
  res_before = model.ps_before_sync(action, payload.data)
25
24
  return if res_before == :cancel
26
25
 
@@ -28,20 +27,24 @@ module PubSubModelSync
28
27
  model.ps_after_sync(action, payload.data)
29
28
  end
30
29
 
31
- def publish(payload)
32
- log("Publishing message: #{[payload]}") if config.debug
33
- config.on_before_publish.call(payload)
30
+ def publish(payload, raise_error: false)
31
+ if config.on_before_publish.call(payload) == :cancel
32
+ log("Publish message cancelled: #{payload}") if config.debug
33
+ return
34
+ end
35
+
36
+ log("Publishing message: #{[payload]}")
34
37
  connector.publish(payload)
35
38
  config.on_after_publish.call(payload)
36
39
  rescue => e
37
- notify_error(e, payload)
40
+ raise_error ? raise : notify_error(e, payload)
38
41
  end
39
42
 
40
43
  private
41
44
 
42
45
  def notify_error(exception, payload)
43
46
  info = [payload, exception.message, exception.backtrace]
44
- res = config.on_publish_error.call(exception, payload)
47
+ res = config.on_error_publish.call(exception, { payload: payload })
45
48
  log("Error publishing: #{info}", :error) if res != :skip_log
46
49
  end
47
50
  end
@@ -26,11 +26,23 @@ module PubSubModelSync
26
26
  end
27
27
 
28
28
  def process!
29
+ process do |publisher|
30
+ publisher.raise_error = true
31
+ end
32
+ end
33
+
34
+ def process
29
35
  publisher = PubSubModelSync::MessageProcessor.new(self)
36
+ yield(publisher) if block_given?
30
37
  publisher.process
31
38
  end
32
39
 
33
40
  def publish!
41
+ klass = PubSubModelSync::MessagePublisher
42
+ klass.publish(self, raise_error: true)
43
+ end
44
+
45
+ def publish
34
46
  klass = PubSubModelSync::MessagePublisher
35
47
  klass.publish(self)
36
48
  end
@@ -12,7 +12,7 @@ module PubSubModelSync
12
12
  end
13
13
 
14
14
  def payload(model, action)
15
- { data: payload_data(model), attrs: payload_attrs(model, action) }
15
+ PubSubModelSync::Payload.new(payload_data(model), payload_attrs(model, action))
16
16
  end
17
17
 
18
18
  private
@@ -11,13 +11,12 @@ module PubSubModelSync
11
11
  false
12
12
  end
13
13
 
14
- # TODO: make it using respond_to?(:ps_skip_sync?)
15
14
  # before preparing data to sync
16
15
  def ps_skip_sync?(_action)
17
16
  false
18
17
  end
19
18
 
20
- # before delivering data
19
+ # before delivering data (return :cancel to cancel sync)
21
20
  def ps_before_sync(_action, _data); end
22
21
 
23
22
  # after delivering data
@@ -64,7 +63,7 @@ module PubSubModelSync
64
63
 
65
64
  def ps_register_callback(action, publisher)
66
65
  after_commit(on: action) do |model|
67
- disabled = PubSubModelSync::Config.disabled
66
+ disabled = PubSubModelSync::Config.disabled_callback_publisher.call(model, action)
68
67
  if !disabled && !model.ps_skip_callback?(action)
69
68
  klass = PubSubModelSync::MessagePublisher
70
69
  klass.publish_model(model, action.to_sym, publisher)
@@ -4,6 +4,8 @@ require 'pub_sub_model_sync/payload'
4
4
  module PubSubModelSync
5
5
  class ServiceBase < PubSubModelSync::Base
6
6
  SERVICE_KEY = 'service_model_sync'
7
+ PUBLISH_SETTINGS = {}.freeze
8
+ LISTEN_SETTINGS = {}.freeze
7
9
 
8
10
  def listen_messages
9
11
  raise 'method :listen_messages must be defined in service'
@@ -18,7 +18,7 @@ module PubSubModelSync
18
18
 
19
19
  def listen_messages
20
20
  @subscription = subscribe_to_topic
21
- @subscriber = subscription.listen(&method(:process_message))
21
+ @subscriber = subscription.listen(LISTEN_SETTINGS, &method(:process_message))
22
22
  log('Listener starting...')
23
23
  subscriber.start
24
24
  log('Listener started')
@@ -28,7 +28,7 @@ module PubSubModelSync
28
28
  end
29
29
 
30
30
  def publish(payload)
31
- topic.publish(payload.to_json, { SERVICE_KEY => true })
31
+ topic.publish(payload.to_json, { SERVICE_KEY => true }.merge(PUBLISH_SETTINGS))
32
32
  end
33
33
 
34
34
  def stop
@@ -39,8 +39,8 @@ module PubSubModelSync
39
39
  private
40
40
 
41
41
  def subscribe_to_topic
42
- topic.subscription(config.subscription_name) ||
43
- topic.subscribe(config.subscription_name)
42
+ topic.subscription(config.subscription_key) ||
43
+ topic.subscribe(config.subscription_key)
44
44
  end
45
45
 
46
46
  def process_message(received_message)
@@ -10,17 +10,17 @@ module PubSubModelSync
10
10
  cattr_accessor :producer
11
11
  attr_accessor :config, :service, :consumer
12
12
 
13
- CONSUMER_GROUP = 'service_model_sync'
14
-
15
13
  def initialize
16
14
  @config = PubSubModelSync::Config
17
- @service = Kafka.new(*config.kafka_connection)
15
+ settings = config.kafka_connection
16
+ settings[1][:client_id] ||= config.subscription_key
17
+ @service = Kafka.new(*settings)
18
18
  end
19
19
 
20
20
  def listen_messages
21
21
  log('Listener starting...')
22
22
  start_consumer
23
- consumer.each_message(&method(:process_message))
23
+ consumer.each_message(LISTEN_SETTINGS, &method(:process_message))
24
24
  rescue PubSubModelSync::Runner::ShutDown
25
25
  log('Listener stopped')
26
26
  rescue => e
@@ -28,7 +28,11 @@ module PubSubModelSync
28
28
  end
29
29
 
30
30
  def publish(payload)
31
- producer.produce(payload.to_json, message_settings)
31
+ settings = {
32
+ topic: config.topic_name,
33
+ headers: { SERVICE_KEY => true }
34
+ }.merge(PUBLISH_SETTINGS)
35
+ producer.produce(payload.to_json, settings)
32
36
  producer.deliver_messages
33
37
  end
34
38
 
@@ -39,12 +43,8 @@ module PubSubModelSync
39
43
 
40
44
  private
41
45
 
42
- def message_settings
43
- { topic: config.topic_name, headers: { SERVICE_KEY => true } }
44
- end
45
-
46
46
  def start_consumer
47
- @consumer = service.consumer(group_id: CONSUMER_GROUP)
47
+ @consumer = service.consumer(group_id: config.subscription_key)
48
48
  consumer.subscribe(config.topic_name)
49
49
  end
50
50
 
@@ -40,6 +40,7 @@ module PubSubModelSync
40
40
 
41
41
  def stop
42
42
  log('Listener stopping...')
43
+ channel&.close
43
44
  service.close
44
45
  end
45
46
 
@@ -48,12 +49,17 @@ module PubSubModelSync
48
49
  def message_settings
49
50
  {
50
51
  routing_key: queue.name,
51
- type: SERVICE_KEY
52
- }
52
+ type: SERVICE_KEY,
53
+ persistent: true
54
+ }.merge(PUBLISH_SETTINGS)
55
+ end
56
+
57
+ def queue_settings
58
+ { durable: true, auto_delete: false }
53
59
  end
54
60
 
55
61
  def subscribe_settings
56
- { manual_ack: false }
62
+ { manual_ack: false }.merge(LISTEN_SETTINGS)
57
63
  end
58
64
 
59
65
  def process_message(_delivery_info, meta_info, payload)
@@ -65,8 +71,7 @@ module PubSubModelSync
65
71
  def subscribe_to_queue
66
72
  service.start
67
73
  @channel = service.create_channel
68
- queue_settings = { durable: true, auto_delete: false }
69
- @queue = channel.queue(config.queue_name, queue_settings)
74
+ @queue = channel.queue(config.subscription_key, queue_settings)
70
75
  subscribe_to_exchange
71
76
  end
72
77
 
@@ -2,7 +2,8 @@
2
2
 
3
3
  module PubSubModelSync
4
4
  class Subscriber
5
- attr_accessor :klass, :action, :attrs, :settings
5
+ attr_accessor :klass, :action, :attrs, :settings, :identifiers
6
+ attr_reader :payload
6
7
 
7
8
  # @param settings: (Hash) { id: :id, direct_mode: false,
8
9
  # from_klass: klass, from_action: action }
@@ -13,50 +14,53 @@ module PubSubModelSync
13
14
  @action = action
14
15
  @attrs = attrs
15
16
  @settings = def_settings.merge(settings)
17
+ @identifiers = Array(settings[:id]).map(&:to_sym)
16
18
  end
17
19
 
18
- def eval_message(message)
20
+ def process!(payload)
21
+ @payload = payload
19
22
  if settings[:direct_mode]
20
- run_class_message(message)
23
+ run_class_message
21
24
  else
22
- run_model_message(message)
25
+ run_model_message
23
26
  end
24
27
  end
25
28
 
26
29
  private
27
30
 
28
- def run_class_message(message)
31
+ def run_class_message
29
32
  model_class = klass.constantize
30
- model_class.send(action, message)
33
+ model_class.send(action, payload.data)
31
34
  end
32
35
 
33
36
  # support for: create, update, destroy
34
- def run_model_message(message)
35
- model = find_model(message)
37
+ def run_model_message
38
+ model = find_model
39
+ return if model.ps_before_save_sync(payload) == :cancel
40
+
36
41
  if action == :destroy
37
42
  model.destroy!
38
43
  else
39
- populate_model(model, message)
40
- return if action == :update && !model.ps_subscriber_changed?(message)
44
+ populate_model(model)
45
+ return if action == :update && !model.ps_subscriber_changed?(payload.data)
41
46
 
42
47
  model.save!
43
48
  end
44
49
  end
45
50
 
46
- def find_model(message)
51
+ def find_model
47
52
  model_class = klass.constantize
48
- return model_class.ps_find_model(message) if model_class.respond_to?(:ps_find_model)
53
+ return model_class.ps_find_model(payload.data) if model_class.respond_to?(:ps_find_model)
49
54
 
50
- model_class.where(model_identifiers(message)).first_or_initialize
55
+ model_class.where(model_identifiers).first_or_initialize
51
56
  end
52
57
 
53
- def model_identifiers(message)
54
- identifiers = Array(settings[:id])
55
- identifiers.map { |key| [key, message[key.to_sym]] }.to_h
58
+ def model_identifiers
59
+ identifiers.map { |key| [key, payload.data[key.to_sym]] }.to_h
56
60
  end
57
61
 
58
- def populate_model(model, message)
59
- values = message.slice(*attrs)
62
+ def populate_model(model)
63
+ values = payload.data.slice(*attrs).except(*identifiers)
60
64
  values.each do |attr, value|
61
65
  model.send("#{attr}=", value)
62
66
  end
@@ -12,6 +12,10 @@ module PubSubModelSync
12
12
  changed?
13
13
  end
14
14
 
15
+ # permit to apply custom actions before applying sync
16
+ # @return (nil|:cancel): nil to continue sync OR :cancel to skip sync
17
+ def ps_before_save_sync(_payload); end
18
+
15
19
  module ClassMethods
16
20
  def ps_subscribe(attrs, actions: nil, from_klass: name, id: :id)
17
21
  settings = { id: id, from_klass: from_klass }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PubSubModelSync
4
- VERSION = '0.5.0.1'
4
+ VERSION = '0.5.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pub_sub_model_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.1
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Owen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-22 00:00:00.000000000 Z
11
+ date: 2021-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails