noticed 1.3.2 → 1.6.0

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: 2362015405a07454aa743ec5709ede4af768866abf27499dce3754b37ac6f4f9
4
- data.tar.gz: 05e36982fe6d3ed4d3cca6929271cc0382be5167fb4c6967396ae6969f3059fe
3
+ metadata.gz: eade1cdb53653ae77fa61a1348340402ea37625188677a16baddda26bc42bd49
4
+ data.tar.gz: 11d1d9ba60517005306714fc028fd312bbee7bef489d19218e7ba5c6938e22eb
5
5
  SHA512:
6
- metadata.gz: ea23c339c18177f234c2d541ababb78cda5ec408100ff828e6a1cd5678dabbfabf6f1bc79c7a129edaf22286754e2e741e611c2b0fc319bcdac10e00fc6fd66f
7
- data.tar.gz: 4f0f7b8c0552683e7e8014a36ebe1d724bfd97baa3056f8483a40a94881bbd4ecbe6527b15a9ce2875d24dba7a767ee88d474b986001bd9974c1eca249a2d6ff
6
+ metadata.gz: '08b57a6181fa23484fa7c21eb7153a75c2bb05750532d2c649a8bc46e30b57be8041039802396167e639fede5595c64bb09d683eaeb1f23a0b0d346f2e76ca5e'
7
+ data.tar.gz: cc01ee47a638c02f1e5311c1433735607052130be9b4beaf61ced7482fd31910ab8c8a17915ff9c60a50bccddbc86bcb14f44519d8119632a95a1eba214f22a4
data/README.md CHANGED
@@ -15,6 +15,8 @@ Currently, we support these notification delivery methods out of the box:
15
15
  * Microsoft Teams
16
16
  * Twilio (SMS)
17
17
  * Vonage / Nexmo (SMS)
18
+ * iOS Apple Push Notifications
19
+ * Firebase Cloud Messaging (Android and more)
18
20
 
19
21
  And you can easily add new notification types for any other delivery methods.
20
22
 
@@ -104,9 +106,10 @@ end
104
106
 
105
107
  **Shared Options**
106
108
 
107
- * `if: :method_name` - Calls `method_name`and cancels delivery method if `false` is returned
108
- * `unless: :method_name` - Calls `method_name`and cancels delivery method if `true` is returned
109
+ * `if: :method_name` - Calls `method_name` and cancels delivery method if `false` is returned
110
+ * `unless: :method_name` - Calls `method_name` and cancels delivery method if `true` is returned
109
111
  * `delay: ActiveSupport::Duration` - Delays the delivery for the given duration of time
112
+ * `delay: :method_name` - Calls `method_name which should return an `ActiveSupport::Duration` and delays the delivery for the given duration of time
110
113
 
111
114
  ##### Helper Methods
112
115
 
@@ -159,6 +162,10 @@ For example:
159
162
 
160
163
  `t(".message")` looks up `en.notifications.new_comment.message`
161
164
 
165
+ Or when notification class is in module:
166
+
167
+ `t(".message") # in Admin::NewComment` looks up `en.notifications.admin.new_comment.message`
168
+
162
169
  ##### User Preferences
163
170
 
164
171
  You can use the `if:` and `unless: ` options on your delivery methods to check the user's preferences and skip processing if they have disabled that type of notification.
@@ -175,184 +182,76 @@ class CommentNotification < Noticed::Base
175
182
  end
176
183
  ```
177
184
 
178
- ## 🚛 Delivery Methods
179
-
180
- The delivery methods are designed to be modular so you can customize the way each type gets delivered.
181
-
182
- For example, emails will require a subject, body, and email address while an SMS requires a phone number and simple message. You can define the formats for each of these in your Notification and the delivery method will handle the processing of it.
183
-
184
- ### Database
185
-
186
- Writes notification to the database.
187
-
188
- `deliver_by :database`
189
-
190
- **Note:** Database notifications are special in that they will run before the other delivery methods. We do this so you can reference the database record ID in other delivery methods. For that same reason, the delivery can't be delayed (via the `delay` option) or an error will be raised.
191
-
192
- ##### Options
193
-
194
- * `association` - *Optional*
195
-
196
- The name of the database association to use. Defaults to `:notifications`
197
-
198
- * `format: :format_for_database` - *Optional*
199
-
200
- Use a custom method to define the attributes saved to the database
201
-
202
- ### Email
203
-
204
- Sends an email notification. Emails will always be sent with `deliver_later`
205
-
206
- `deliver_by :email, mailer: "UserMailer"`
207
-
208
- ##### Options
209
-
210
- * `mailer` - **Required**
211
-
212
- The mailer that should send the email
213
-
214
- * `method: :invoice_paid` - *Optional*
215
-
216
- Used to customize the method on the mailer that is called
217
-
218
- * `format: :format_for_email` - *Optional*
219
-
220
- Use a custom method to define the params sent to the mailer. `recipient` will be merged into the params.
221
-
222
- ### ActionCable
223
-
224
- Sends a notification to the browser via websockets (ActionCable channel by default).
225
-
226
- `deliver_by :action_cable`
227
-
228
- ##### Options
229
-
230
- * `format: :format_for_action_cable` - *Optional*
231
-
232
- Use a custom method to define the Hash sent through ActionCable
233
-
234
- * `channel` - *Optional*
235
-
236
- Override the ActionCable channel used to send notifications.
237
-
238
- Defaults to `Noticed::NotificationChannel`
239
-
240
- ### Slack
241
-
242
- Sends a Slack notification via webhook.
243
-
244
- `deliver_by :slack`
245
-
246
- ##### Options
247
-
248
- * `format: :format_for_slack` - *Optional*
249
-
250
- Use a custom method to define the payload sent to Slack. Method should return a Hash.
251
-
252
- * `url: :url_for_slack` - *Optional*
253
-
254
- Use a custom method to retrieve the Slack Webhook URL. Method should return a String.
185
+ ## 🐞 Debugging
255
186
 
256
- Defaults to `Rails.application.credentials.slack[:notification_url]`
187
+ In order to figure out what's up when you run in to errors, you can set the `debug` parameter to `true` in your notification, which will give you a more detailed error message about what went wrong.
257
188
 
258
- ### Microsoft Teams
189
+ Example:
259
190
 
260
- Sends a Teams notification via webhook.
261
-
262
- `deliver_by :microsoft_teams`
263
-
264
- #### Options
265
-
266
- * `format: :format_for_teams` - *Optional*
267
-
268
- Use a custom method to define the payload sent to Microsoft Teams. Method should return a Hash.
269
- Documentation for posting via Webhooks available at: https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook
270
-
271
- ```ruby
272
- {
273
- title: "This is the title for the card",
274
- text: "This is the body text for the card",
275
- sections: [{activityTitle: "Section Title", activityText: "Section Text"}],
276
- "potentialAction": [{
277
- "@type": "OpenUri",
278
- name: "Button Text",
279
- targets: [{
280
- os: "default",
281
- uri: "https://example.com/foo/action"
282
- }]
283
- }]
284
-
285
- }
286
- ```
287
-
288
- * `url: :url_for_teams_channel`: - *Optional*
289
-
290
- Use a custom method to retrieve the MS Teams Webhook URL. Method should return a string.
291
-
292
- Defaults to `Rails.application.credentials.microsoft_teams[:notification_url]`
293
-
294
- ### Twilio SMS
295
-
296
- Sends an SMS notification via Twilio.
297
-
298
- `deliver_by :twilio`
191
+ ```ruby
192
+ deliver_by :slack, debug: true
193
+ ```
299
194
 
300
- ##### Options
195
+ ## ✅ Best Practices
301
196
 
302
- * `credentials: :get_twilio_credentials` - *Optional*
197
+ ### Creating a notification from an Active Record callback
303
198
 
304
- Use a custom method to retrieve the credentials for Twilio. Method should return a Hash with `:account_sid`, `:auth_token` and `:phone_number` keys.
199
+ A common use case is to trigger a notification when a record is created. For example,
305
200
 
306
- Defaults to `Rails.application.credentials.twilio[:account_sid]` and `Rails.application.credentials.twilio[:auth_token]`
201
+ ```ruby
202
+ class Message < ApplicationRecord
203
+ belongs_to :recipient, class_name: "User"
307
204
 
308
- * `url: :get_twilio_url` - *Optional*
205
+ after_create_commit :notify_recipient
309
206
 
310
- Use a custom method to retrieve the Twilio URL. Method should return the Twilio API url as a string.
207
+ private
311
208
 
312
- Defaults to `"https://api.twilio.com/2010-04-01/Accounts/#{twilio_credentials(recipient)[:account_sid]}/Messages.json"`
209
+ def notify_recipient
210
+ NewMessageNotification.with(message: self).deliver_later(recipient)
211
+ end
212
+ ```
313
213
 
314
- * `format: :format_for_twilio` - *Optional*
214
+ If you are creating the notification on a background job (i.e. via `#deliver_later`), make sure you use a `commit` hook such as `after_create_commit` or `after_commit`.
315
215
 
316
- Use a custom method to define the payload sent to Twilio. Method should return a Hash.
216
+ Using `after_create` might cause the notification delivery methods to fail. This is because the job was enqueued while inside a database transaction, and the `Message` record might not yet be saved to the database.
317
217
 
318
- Defaults to:
218
+ A common symptom of this problem is undelivered notifications and the following error in your logs.
319
219
 
320
- ```ruby
321
- {
322
- Body: notification.params[:message],
323
- From: twilio_credentials[:number],
324
- To: recipient.phone_number
325
- }
326
- ```
220
+ > `Discarded Noticed::DeliveryMethods::Email due to a ActiveJob::DeserializationError.`
327
221
 
328
- ### Vonage SMS
222
+ ### Renaming notifications
329
223
 
330
- Sends an SMS notification via Vonage / Nexmo.
224
+ If you rename the class of a notification object your existing queries can break. This is because Noticed serializes the class name and sets it to the `type` column on the `Notification` record.
331
225
 
332
- `deliver_by :vonage`
226
+ You can catch these errors at runtime by using `YourNotificationClassName.name` instead of hardcoding the string when performing a query.
333
227
 
334
- ##### Options
228
+ ```ruby
229
+ Notification.where(type: YourNotificationClassName.name) # good
230
+ Notification.where(type: "YourNotificationClassName") # bad
231
+ ```
335
232
 
336
- * `credentials: :get_credentials` - *Optional*
233
+ When renaming a notification class you will need to backfill existing notifications to reference the new name.
337
234
 
338
- Use a custom method for retrieving credentials. Method should return a Hash with `:api_key` and `:api_secret` keys.
235
+ ```ruby
236
+ Notification.where(type: "OldNotificationClassName").update_all(type: NewNotificationClassName.name)
237
+ ```
339
238
 
340
- Defaults to `Rails.application.credentials.vonage[:api_key]` and `Rails.application.credentials.vonage[:api_secret]`
239
+ ## 🚛 Delivery Methods
341
240
 
342
- * `deliver_by :vonage, format: :format_for_vonage` - *Optional*
241
+ The delivery methods are designed to be modular so you can customize the way each type gets delivered.
343
242
 
344
- Use a custom method to generate the params sent to Vonage. Method should return a Hash. Defaults to:
243
+ For example, emails will require a subject, body, and email address while an SMS requires a phone number and simple message. You can define the formats for each of these in your Notification and the delivery method will handle the processing of it.
345
244
 
346
- ```ruby
347
- {
348
- api_key: vonage_credentials[:api_key],
349
- api_secret: vonage_credentials[:api_secret],
350
- from: notification.params[:from],
351
- text: notification.params[:body],
352
- to: notification.params[:to],
353
- type: "unicode"
354
- }
355
- ```
245
+ * [Database](docs/delivery_methods/database.md)
246
+ * [Email](docs/delivery_methods/email.md)
247
+ * [ActionCable](docs/delivery_methods/action_cable.md)
248
+ * [iOS Apple Push Notifications](docs/delivery_methods/ios.md)
249
+ * [Microsoft Teams](docs/delivery_methods/microsoft_teams.md)
250
+ * [Slack](docs/delivery_methods/slack.md)
251
+ * [Test](docs/delivery_methods/test.md)
252
+ * [Twilio](docs/delivery_methods/twilio.md)
253
+ * [Vonage](docs/delivery_methods/vonage.md)
254
+ * [Firebase Cloud Messaging](docs/delivery_methods/fcm.md)
356
255
 
357
256
  ### Fallback Notifications
358
257
 
@@ -371,16 +270,24 @@ You can also configure multiple fallback options:
371
270
 
372
271
  ```ruby
373
272
  class CriticalSystemNotification < Noticed::Base
273
+ deliver_by :database
374
274
  deliver_by :slack
375
- deliver_by :email, mailer: 'CriticalSystemMailer', delay: 10.minutes, unless: :read?
376
- deliver_by :twilio, delay: 20.minutes, unless: :read?
275
+ deliver_by :email, mailer: 'CriticalSystemMailer', delay: 10.minutes, if: :unread?
276
+ deliver_by :twilio, delay: 20.minutes, if: :unread?
377
277
  end
378
278
  ```
379
279
 
380
- In this scenario, you can create an escalating notification that starts with a ping in Slack, then emails the team, and then finally sends an SMS to the on-call phone.
280
+ In this scenario, you have created an escalating notification system that
281
+
282
+ - Immediately creates a record in the database (for display directly in the app)
283
+ - Immediately issues a ping in Slack.
284
+ - If the notification remains unread after 10 minutes, it emails the team.
285
+ - If the notification remains unread after 20 minutes, it sends an SMS to the on-call phone.
381
286
 
382
287
  You can mix and match the options and delivery methods to suit your application specific needs.
383
288
 
289
+ Please note that to implement this pattern, it is essential `deliver_by :database` is one among the different delivery methods specified. Without this, a database record of the notification will not be created.
290
+
384
291
  ### 🚚 Custom Delivery Methods
385
292
 
386
293
  To generate a custom delivery method, simply run
@@ -463,22 +370,6 @@ class DeliveryMethods::Discord < Noticed::DeliveryMethods::Base
463
370
  end
464
371
  ```
465
372
 
466
- #### Limitations
467
-
468
- Rails 6.1+ can serialize Class and Module objects as arguments to ActiveJob. The following syntax should work for Rails 6.1+:
469
-
470
- ```ruby
471
- deliver_by DeliveryMethods::Discord
472
- ```
473
-
474
- For Rails 6.0, you must pass strings of the class names in the `deliver_by` options.
475
-
476
- ```ruby
477
- deliver_by :discord, class: "DeliveryMethods::Discord"
478
- ```
479
-
480
- We recommend the Rails 6.0 compatible options to prevent confusion.
481
-
482
373
  ### 📦 Database Model
483
374
 
484
375
  The Notification database model includes several helpful features to make working with database notifications easier.
@@ -550,7 +441,7 @@ class Post < ApplicationRecord
550
441
  has_noticed_notifications
551
442
 
552
443
  # You can override the param_name, the notification model name, or disable the before_destroy callback
553
- has_noticed_notifications param_name: :parent, destroy: false, model: "Notification"
444
+ has_noticed_notifications param_name: :parent, destroy: false, model_name: "Notification"
554
445
  end
555
446
 
556
447
  # Create a CommentNotification with a post param
@@ -564,7 +455,7 @@ CommentNotification.with(parent: @post).deliver(user)
564
455
 
565
456
  #### Handling Deleted Records
566
457
 
567
- If you create a notification but delete the associated record and forgot `has_noticed_notifications` on the model, the jobs for sending the notification will not be able to find the record when ActiveJob deserializes. You can discord the job on these errors by adding the following to `ApplicationJob`:
458
+ If you create a notification but delete the associated record and forgot `has_noticed_notifications` on the model, the jobs for sending the notification will not be able to find the record when ActiveJob deserializes. You can discard the job on these errors by adding the following to `ApplicationJob`:
568
459
 
569
460
  ```ruby
570
461
  class ApplicationJob < ActiveJob::Base
@@ -576,5 +467,13 @@ end
576
467
 
577
468
  This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `standardrb` before submitting pull requests.
578
469
 
470
+ Running tests against multiple databases locally:
471
+
472
+ ```
473
+ DATABASE_URL=sqlite3:noticed_test rails test
474
+ DATABASE_URL=mysql2://root:@127.0.0.1/noticed_test rails test
475
+ DATABASE_URL=postgres://127.0.0.1/noticed_test rails test
476
+ ```
477
+
579
478
  ## 📝 License
580
479
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -42,14 +42,22 @@ module Noticed
42
42
  end
43
43
 
44
44
  def params_column
45
- case ActiveRecord::Base.configurations.configs_for(spec_name: "primary").config["adapter"]
46
- when "postgresql"
45
+ case current_adapter
46
+ when "postgresql", "postgis"
47
47
  "params:jsonb"
48
48
  else
49
49
  # MySQL and SQLite both support json
50
50
  "params:json"
51
51
  end
52
52
  end
53
+
54
+ def current_adapter
55
+ if ActiveRecord::Base.respond_to?(:connection_db_config)
56
+ ActiveRecord::Base.connection_db_config.adapter
57
+ else
58
+ ActiveRecord::Base.connection_config[:adapter]
59
+ end
60
+ end
53
61
  end
54
62
  end
55
63
  end
@@ -3,5 +3,5 @@
3
3
 
4
4
  Next steps:
5
5
  1. Run "rails db:migrate"
6
- 2. Add "has_many :notifications, as: :recipient" to your User model(s).
6
+ 2. Add "has_many :notifications, as: :recipient, dependent: :destroy" to your User model(s).
7
7
  3. Generate notifications with "rails g noticed:notification"
data/lib/noticed/base.rb CHANGED
@@ -9,7 +9,7 @@ module Noticed
9
9
  class_attribute :delivery_methods, instance_writer: false, default: []
10
10
  class_attribute :param_names, instance_writer: false, default: []
11
11
 
12
- # Gives notifications access to the record and recipient when formatting for delivery
12
+ # Gives notifications access to the record and recipient during delivery
13
13
  attr_accessor :record, :recipient
14
14
 
15
15
  delegate :read?, :unread?, to: :record
@@ -21,7 +21,7 @@ module Noticed
21
21
  end
22
22
 
23
23
  # Copy delivery methods from parent
24
- def inherited(base) #:nodoc:
24
+ def inherited(base) # :nodoc:
25
25
  base.delivery_methods = delivery_methods.dup
26
26
  base.param_names = param_names.dup
27
27
  super
@@ -31,6 +31,16 @@ module Noticed
31
31
  new(params)
32
32
  end
33
33
 
34
+ # Shortcut for delivering without params
35
+ def deliver(recipients)
36
+ new.deliver(recipients)
37
+ end
38
+
39
+ # Shortcut for delivering later without params
40
+ def deliver_later(recipients)
41
+ new.deliver_later(recipients)
42
+ end
43
+
34
44
  def params(*names)
35
45
  param_names.concat Array.wrap(names)
36
46
  end
@@ -65,28 +75,31 @@ module Noticed
65
75
  @params || {}
66
76
  end
67
77
 
78
+ def clear_recipient
79
+ self.recipient = nil
80
+ end
81
+
68
82
  private
69
83
 
70
84
  # Runs all delivery methods for a notification
71
85
  def run_delivery(recipient, enqueue: true)
72
86
  delivery_methods = self.class.delivery_methods.dup
73
87
 
74
- # Set recipient to instance var so it is available to Notification class
75
- @recipient = recipient
88
+ self.recipient = recipient
76
89
 
77
90
  # Run database delivery inline first if it exists so other methods have access to the record
78
91
  if (index = delivery_methods.find_index { |m| m[:name] == :database })
79
92
  delivery_method = delivery_methods.delete_at(index)
80
- @record = run_delivery_method(delivery_method, recipient: recipient, enqueue: false)
93
+ self.record = run_delivery_method(delivery_method, recipient: recipient, enqueue: false, record: nil)
81
94
  end
82
95
 
83
96
  delivery_methods.each do |delivery_method|
84
- run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue)
97
+ run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue, record: record)
85
98
  end
86
99
  end
87
100
 
88
101
  # Actually runs an individual delivery
89
- def run_delivery_method(delivery_method, recipient:, enqueue:)
102
+ def run_delivery_method(delivery_method, recipient:, enqueue:, record:)
90
103
  args = {
91
104
  notification_class: self.class.name,
92
105
  options: delivery_method[:options],
@@ -103,6 +116,9 @@ module Noticed
103
116
 
104
117
  # Always perfrom later if a delay is present
105
118
  if (delay = delivery_method.dig(:options, :delay))
119
+ # Dynamic delays with metho calls or
120
+ delay = send(delay) if delay.is_a? Symbol
121
+
106
122
  method.set(wait: delay, queue: queue).perform_later(args)
107
123
  elsif enqueue
108
124
  method.set(queue: queue).perform_later(args)
data/lib/noticed/coder.rb CHANGED
@@ -3,6 +3,8 @@ module Noticed
3
3
  def self.load(data)
4
4
  return if data.nil?
5
5
  ActiveJob::Arguments.send(:deserialize_argument, data)
6
+ rescue ActiveRecord::RecordNotFound => error
7
+ {noticed_error: error.message, original_params: data}
6
8
  end
7
9
 
8
10
  def self.dump(data)
@@ -2,7 +2,7 @@ module Noticed
2
2
  module DeliveryMethods
3
3
  class ActionCable < Base
4
4
  def deliver
5
- channel.broadcast_to recipient, format
5
+ channel.broadcast_to stream, format
6
6
  end
7
7
 
8
8
  private
@@ -30,6 +30,18 @@ module Noticed
30
30
  end
31
31
  end
32
32
  end
33
+
34
+ def stream
35
+ value = options[:stream]
36
+ case value
37
+ when String
38
+ value
39
+ when Symbol
40
+ notification.send(value)
41
+ else
42
+ recipient
43
+ end
44
+ end
33
45
  end
34
46
  end
35
47
  end
@@ -10,7 +10,7 @@ module Noticed
10
10
 
11
11
  class << self
12
12
  # Copy option names from parent
13
- def inherited(base) #:nodoc:
13
+ def inherited(base) # :nodoc:
14
14
  base.option_names = option_names.dup
15
15
  super
16
16
  end
@@ -29,9 +29,9 @@ module Noticed
29
29
  end
30
30
  end
31
31
 
32
- def perform(args)
33
- @notification = args[:notification_class].constantize.new(args[:params])
34
- @options = args[:options]
32
+ def assign_args(args)
33
+ @notification = args.fetch(:notification_class).constantize.new(args[:params])
34
+ @options = args[:options] || {}
35
35
  @params = args[:params]
36
36
  @recipient = args[:recipient]
37
37
  @record = args[:record]
@@ -39,6 +39,11 @@ module Noticed
39
39
  # Make notification aware of database record and recipient during delivery
40
40
  @notification.record = args[:record]
41
41
  @notification.recipient = args[:recipient]
42
+ self
43
+ end
44
+
45
+ def perform(args)
46
+ assign_args(args)
42
47
 
43
48
  return if (condition = @options[:if]) && !@notification.send(condition)
44
49
  return if (condition = @options[:unless]) && @notification.send(condition)
@@ -57,16 +62,16 @@ module Noticed
57
62
  # Helper method for making POST requests from delivery methods
58
63
  #
59
64
  # Usage:
60
- # post("http://example.com", basic_auth: {user:, pass:}, json: {}, form: {})
65
+ # post("http://example.com", basic_auth: {user:, pass:}, headers: {}, json: {}, form: {})
61
66
  #
62
67
  def post(url, args = {})
68
+ options ||= {}
63
69
  basic_auth = args.delete(:basic_auth)
70
+ headers = args.delete(:headers)
64
71
 
65
- request = if basic_auth
66
- HTTP.basic_auth(user: basic_auth[:user], pass: basic_auth[:pass])
67
- else
68
- HTTP
69
- end
72
+ request = HTTP
73
+ request = request.basic_auth(user: basic_auth[:user], pass: basic_auth[:pass]) if basic_auth
74
+ request = request.headers(headers) if headers
70
75
 
71
76
  response = request.post(url, args)
72
77
 
@@ -76,6 +81,8 @@ module Noticed
76
81
  end
77
82
 
78
83
  if !options[:ignore_failure] && !response.status.success?
84
+ puts response.status
85
+ puts response.body
79
86
  raise ResponseUnsuccessful.new(response)
80
87
  end
81
88
 
@@ -4,17 +4,42 @@ module Noticed
4
4
  option :mailer
5
5
 
6
6
  def deliver
7
- mailer.with(format).send(method.to_sym).deliver_now
7
+ if options[:enqueue]
8
+ mailer.with(format).send(method.to_sym).deliver_later
9
+ else
10
+ mailer.with(format).send(method.to_sym).deliver_now
11
+ end
8
12
  end
9
13
 
10
14
  private
11
15
 
16
+ # mailer: "UserMailer"
17
+ # mailer: UserMailer
18
+ # mailer: :my_method - `my_method` should return Class
12
19
  def mailer
13
- options.fetch(:mailer).constantize
20
+ option = options.fetch(:mailer)
21
+ case option
22
+ when String
23
+ option.constantize
24
+ when Symbol
25
+ notification.send(option)
26
+ else
27
+ option
28
+ end
14
29
  end
15
30
 
31
+ # Method should be a symbol
32
+ #
33
+ # If notification responds to symbol, call that method and use return value
34
+ # If notification does not respond to symbol, use the symbol for the mailer method
35
+ # Otherwise, use the underscored notification class name as the mailer method
16
36
  def method
17
- options[:method] || notification.class.name.underscore
37
+ method_name = options[:method]&.to_sym
38
+ if method_name.present?
39
+ notification.respond_to?(method_name) ? notification.send(method_name) : method_name
40
+ else
41
+ notification.class.name.underscore
42
+ end
18
43
  end
19
44
 
20
45
  def format