noticed 1.2.10 → 1.2.15

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: 49ea4996a79f9bb4b9070ebe4801c0927e8dddd357c9a4f8a7812fe6609a9eb5
4
- data.tar.gz: aa5852613e11f73c2c263c961b49f1b54f7d77b414df59ed282703aa77757057
3
+ metadata.gz: 69785568f3cfb7b464a3dfbb7ce8bd0813acbdcd3f96059122c2a9b24ade12d2
4
+ data.tar.gz: 3c9464383b48f2df3605b7aa1062519e867f2ebfae7dde21ccc25ac69afab258
5
5
  SHA512:
6
- metadata.gz: 561f2719087ff38f45ad8230e1f5a7f7bc9adb6f192f39d1217c7b5df5acde0606103a015f5c87523b438baf5be6f79a07153b5b0ef5bb6037445fa2bd94a382
7
- data.tar.gz: 57c32c69975a7584f2e44dd41ef4c431fb8b33e629e92494a2988aabdde10feda18ce0224f08855b9118704f3ea7199a752732eb1306ef781ee51ea410b23a04
6
+ metadata.gz: 539e60472bad43dd44239ecbcbd79ad9dff86cb8105d7923657e62ffa6b1fe9a3ef6ced17b823597e907645ec5837985aaee7cc7da8b2f89f7d85fa1b6b881bd
7
+ data.tar.gz: 34bb2249fafab5002d569ddd267a3944e43e03b51a793ed162c3166900699b658efdb8ace15a3a6dca29000aa68787046732d2d1df88b31468fc096ffd18641f
data/README.md CHANGED
@@ -78,7 +78,7 @@ To add delivery methods, simply `include` the module for the delivery methods yo
78
78
  class CommentNotification < Noticed::Base
79
79
  deliver_by :database
80
80
  deliver_by :action_cable
81
- deliver_by :email, if: :email_notifications?
81
+ deliver_by :email, mailer: 'CommentMailer', if: :email_notifications?
82
82
 
83
83
  # I18n helpers
84
84
  def message
@@ -120,7 +120,7 @@ Like ActiveRecord, notifications have several different types of callbacks.
120
120
  ```ruby
121
121
  class CommentNotification < Noticed::Base
122
122
  deliver_by :database
123
- deliver_by :email
123
+ deliver_by :email, mailer: 'CommentMailer'
124
124
 
125
125
  # Callbacks for the entire delivery
126
126
  before_deliver :whatever
@@ -158,7 +158,7 @@ For example:
158
158
 
159
159
  ```ruby
160
160
  class CommentNotification < Noticed::Base
161
- deliver_by :email, if: :email_notifications?
161
+ deliver_by :email, mailer: 'CommentMailer', if: :email_notifications?
162
162
 
163
163
  def email_notifications?
164
164
  recipient.email_notifications?
@@ -311,22 +311,28 @@ Sends an SMS notification via Vonage / Nexmo.
311
311
 
312
312
  ### 🚚 Custom Delivery Methods
313
313
 
314
- You can define a custom delivery method easily by adding a `deliver_by` line with a unique name and class option. The class will be instantiated and should inherit from `Noticed::DeliveryMethods::Base`.
314
+ To generate a custom delivery method, simply run
315
315
 
316
- ```ruby
317
- class MyNotification < Noticed::Base
318
- deliver_by :discord, class: "DiscordNotification"
319
- end
320
- ```
316
+ `rails generate noticed:delivery_method Discord`
317
+
318
+ This will generate a new `DeliveryMethods::Discord` class inside the `app/notifications/delivery_methods` folder, which can be used to deliver notifications to Discord.
321
319
 
322
320
  ```ruby
323
- class DiscordNotification < Noticed::DeliveryMethods::Base
321
+ class DeliveryMethods::Discord < Noticed::DeliveryMethods::Base
324
322
  def deliver
325
323
  # Logic for sending a Discord notification
326
324
  end
327
325
  end
328
326
  ```
329
327
 
328
+ You can use the custom delivery method thus created by adding a `deliver_by` line with a unique name and `class` option in your notification class.
329
+
330
+ ```ruby
331
+ class MyNotification < Noticed::Base
332
+ deliver_by :discord, class: "DeliveryMethods::Discord"
333
+ end
334
+ ```
335
+
330
336
  Delivery methods have access to the following methods and attributes:
331
337
 
332
338
  * `notification` - The instance of the Notification. You can call methods on the notification to let the user easily override formatting and other functionality of the delivery method.
@@ -334,12 +340,46 @@ Delivery methods have access to the following methods and attributes:
334
340
  * `recipient` - The object who should receive the notification. This is typically a User, Account, or other ActiveRecord model.
335
341
  * `params` - The params passed into the notification. This is details about the event that happened. For example, a user commenting on a post would have params of `{ user: User.first }`
336
342
 
343
+ #### Validating options passed to Custom Delivery methods
344
+
345
+ You can validate the options passed to the custom delivery method and raise validation errors. This is helpful for debugging to make sure valid and required options were passed in.
346
+
347
+ To do this, simply override the `self.validate!(options)` method from the `Noticed::DeliveryMethods::Base` class in your Custom Delivery method.
348
+
349
+ ```ruby
350
+ class DeliveryMethods::Discord < Noticed::DeliveryMethods::Base
351
+ def deliver
352
+ # Logic for sending a Discord notification
353
+ end
354
+
355
+ def self.validate!(options)
356
+ unless options.key?(:sent_by)
357
+ raise Noticed::ValidationError, 'the `sent_by` option is missing'
358
+ end
359
+ end
360
+ end
361
+
362
+ class CommentNotification < Noticed::Base
363
+ deliver_by :discord, class: 'DeliveryMethods::Discord'
364
+ end
365
+ ```
366
+
367
+ Now it will raise an error because a required argument is missing.
368
+
369
+ To fix the error, the argument has to be passed correctly. For example:
370
+
371
+ ```ruby
372
+ class CommentNotification < Noticed::Base
373
+ deliver_by :discord, class: 'DeliveryMethods::Discord', sent_by: User.admin.first
374
+ end
375
+ ```
376
+
337
377
  #### Callbacks
338
378
 
339
379
  Callbacks for delivery methods wrap the *actual* delivery of the notification. You can use `before_deliver`, `around_deliver` and `after_deliver` in your custom delivery methods.
340
380
 
341
381
  ```ruby
342
- class DiscordNotification < Noticed::DeliveryMethods::Base
382
+ class DeliveryMethods::Discord < Noticed::DeliveryMethods::Base
343
383
  after_deliver do
344
384
  # Do whatever you want
345
385
  end
@@ -351,13 +391,13 @@ end
351
391
  Rails 6.1+ can serialize Class and Module objects as arguments to ActiveJob. The following syntax should work for Rails 6.1+:
352
392
 
353
393
  ```ruby
354
- deliver_by DiscordNotification
394
+ deliver_by DeliveryMethods::Discord
355
395
  ```
356
396
 
357
397
  For Rails 6.0 and earlier, you must pass strings of the class names in the `deliver_by` options.
358
398
 
359
399
  ```ruby
360
- deliver_by :discord, class: "DiscordNotification"
400
+ deliver_by :discord, class: "DeliveryMethods::Discord"
361
401
  ```
362
402
 
363
403
  We recommend the Rails 6.0 compatible options to prevent confusion.
@@ -401,6 +441,60 @@ Check if read / unread:
401
441
  @notification.unread?
402
442
  ```
403
443
 
444
+ #### Associating Notifications
445
+
446
+ Adding notification associations to your models makes querying and deleting notifications easy and is a pretty critical feature of most applications.
447
+
448
+ For example, in most cases, you'll want to delete notifications for records that are destroyed.
449
+
450
+ ##### JSON Columns
451
+
452
+ If you're using MySQL or Postgresql, the `params` column on the notifications table is in `json` or `jsonb` format and can be queried against directly.
453
+
454
+ For example, we can query the notifications and delete them on destroy like so:
455
+
456
+ ```ruby
457
+ class Post < ApplicationRecord
458
+ def notifications
459
+ # Exact match
460
+ @notifications ||= Notification.where(params: { post: self })
461
+
462
+ # Or Postgres syntax to query the post key in the JSON column
463
+ # @notifications ||= Notification.where("params->'post' = ?", Noticed::Coder.dump(self).to_json)
464
+ end
465
+
466
+ before_destroy :destroy_notifications
467
+
468
+ def destroy_notifications
469
+ notifications.destroy_all
470
+ end
471
+ end
472
+ ```
473
+
474
+ ##### Polymorphic Assocation
475
+
476
+ If your notification is only associated with one model or you're using a `text` column for your params column , then a polymorphic association is what you'll want to use.
477
+
478
+ 1. Add a polymorphic association to the Notification model. `rails g migration AddNotifiableToNotifications notifiable:belongs_to{polymorphic}`
479
+
480
+ 2. Add `has_many :notifications, as: :notifiable, dependent: :destroy` to each model
481
+
482
+ 3. Customize database `format: ` option to write the `notifiable` attribute(s) when saving the notification
483
+
484
+ ```ruby
485
+ class ExampleNotification < Noticed::Base
486
+ deliver_by :database, format: :format_for_database
487
+
488
+ def format_for_database
489
+ {
490
+ notifiable: params.delete(:post),
491
+ type: self.class.name,
492
+ params: params
493
+ }
494
+ end
495
+ end
496
+ ```
497
+
404
498
  ## 🙏 Contributing
405
499
 
406
500
  This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `standardrb` before submitting pull requests.
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/named_base"
4
+
5
+ module Noticed
6
+ module Generators
7
+ class DeliveryMethodGenerator < Rails::Generators::NamedBase
8
+ include Rails::Generators::ResourceHelpers
9
+
10
+ source_root File.expand_path("../templates", __FILE__)
11
+
12
+ desc "Generates a class for a custom delivery method with the given NAME."
13
+
14
+ def generate_notification
15
+ template "delivery_method.rb", "app/notifications/delivery_methods/#{singular_name}.rb"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -22,6 +22,15 @@ module Noticed
22
22
  inject_into_class model_path, class_name, " include Noticed::Model\n"
23
23
  end
24
24
 
25
+ def add_not_nullable
26
+ migration_path = Dir.glob(Rails.root.join("db/migrate/*")).max_by { |f| File.mtime(f) }
27
+
28
+ # Force is required because null: false already exists in the file and Thor isn't smart enough to tell the difference
29
+ insert_into_file migration_path, after: "t.string :type", force: true do
30
+ ", null: false"
31
+ end
32
+ end
33
+
25
34
  def done
26
35
  readme "README" if behavior == :invoke
27
36
  end
@@ -33,7 +42,7 @@ module Noticed
33
42
  end
34
43
 
35
44
  def params_column
36
- case ActiveRecord::Base.connection.instance_values["config"][:adapter]
45
+ case ActiveRecord::Base.configurations.configs_for(spec_name: "primary").config["adapter"]
37
46
  when "mysql"
38
47
  "params:json"
39
48
  when "postgresql"
@@ -0,0 +1,12 @@
1
+ class DeliveryMethods::<%= class_name %> < Noticed::DeliveryMethods::Base
2
+ def deliver
3
+ # Logic for sending the notification
4
+ end
5
+
6
+ # You may override this method to validate options for the delivery method
7
+ # Invalid options should raise a ValidationError
8
+ #
9
+ # def self.validate!(options)
10
+ # raise ValidationError, "required_option missing" unless options[:required_option]
11
+ # end
12
+ end
@@ -8,6 +8,7 @@ module Noticed
8
8
  autoload :Model, "noticed/model"
9
9
  autoload :TextCoder, "noticed/text_coder"
10
10
  autoload :Translation, "noticed/translation"
11
+ autoload :NotificationChannel, "noticed/notification_channel"
11
12
 
12
13
  module DeliveryMethods
13
14
  autoload :Base, "noticed/delivery_methods/base"
@@ -97,13 +97,12 @@ module Noticed
97
97
  }
98
98
 
99
99
  run_callbacks delivery_method[:name] do
100
- klass = get_class(delivery_method[:name], delivery_method[:options])
101
- enqueue ? klass.perform_later(args) : klass.perform_now(args)
100
+ method = delivery_method_for(delivery_method[:name], delivery_method[:options])
101
+ enqueue ? method.perform_later(args) : method.perform_now(args)
102
102
  end
103
103
  end
104
104
 
105
- # Retrieves the correct class for a delivery method
106
- def get_class(name, options)
105
+ def delivery_method_for(name, options)
107
106
  if options[:class]
108
107
  options[:class].constantize
109
108
  else
@@ -111,13 +110,25 @@ module Noticed
111
110
  end
112
111
  end
113
112
 
114
- # Validates that all params are present
115
113
  def validate!
114
+ validate_params_present!
115
+ validate_options_of_delivery_methods!
116
+ end
117
+
118
+ # Validates that all params are present
119
+ def validate_params_present!
116
120
  self.class.param_names.each do |param_name|
117
121
  if params[param_name].nil?
118
122
  raise ValidationError, "#{param_name} is missing."
119
123
  end
120
124
  end
121
125
  end
126
+
127
+ def validate_options_of_delivery_methods!
128
+ delivery_methods.each do |delivery_method|
129
+ method = delivery_method_for(delivery_method[:name], delivery_method[:options])
130
+ method.validate!(delivery_method[:options])
131
+ end
132
+ end
122
133
  end
123
134
  end
@@ -4,11 +4,12 @@ module Noticed
4
4
  extend ActiveModel::Callbacks
5
5
  define_model_callbacks :deliver
6
6
 
7
- attr_reader :notification, :options, :recipient, :record
7
+ attr_reader :notification, :options, :params, :recipient, :record
8
8
 
9
9
  def perform(args)
10
10
  @notification = args[:notification_class].constantize.new(args[:params])
11
11
  @options = args[:options]
12
+ @params = args[:params]
12
13
  @recipient = args[:recipient]
13
14
  @record = args[:record]
14
15
 
@@ -25,6 +26,11 @@ module Noticed
25
26
  raise NotImplementedError, "Delivery methods must implement a deliver method"
26
27
  end
27
28
 
29
+ def self.validate!(options)
30
+ # Override this method in your custom DeliveryMethod class to validate the options
31
+ # and raise error, if invalid.
32
+ end
33
+
28
34
  private
29
35
 
30
36
  # Helper method for making POST requests from delivery methods
@@ -5,6 +5,12 @@ module Noticed
5
5
  mailer.with(format).send(method.to_sym).deliver_later
6
6
  end
7
7
 
8
+ def self.validate!(options)
9
+ unless options.key?(:mailer)
10
+ raise ValidationError, "email delivery method requires a 'mailer' to be specified"
11
+ end
12
+ end
13
+
8
14
  private
9
15
 
10
16
  def mailer
@@ -1,3 +1,3 @@
1
1
  module Noticed
2
- VERSION = "1.2.10"
2
+ VERSION = "1.2.15"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noticed
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.10
4
+ version: 1.2.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-17 00:00:00.000000000 Z
11
+ date: 2020-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -91,10 +91,11 @@ files:
91
91
  - MIT-LICENSE
92
92
  - README.md
93
93
  - Rakefile
94
- - app/channels/noticed/notification_channel.rb
94
+ - lib/generators/noticed/delivery_method_generator.rb
95
95
  - lib/generators/noticed/model_generator.rb
96
96
  - lib/generators/noticed/notification_generator.rb
97
97
  - lib/generators/noticed/templates/README
98
+ - lib/generators/noticed/templates/delivery_method.rb.tt
98
99
  - lib/generators/noticed/templates/notification.rb.tt
99
100
  - lib/noticed.rb
100
101
  - lib/noticed/base.rb
@@ -109,6 +110,7 @@ files:
109
110
  - lib/noticed/delivery_methods/vonage.rb
110
111
  - lib/noticed/engine.rb
111
112
  - lib/noticed/model.rb
113
+ - lib/noticed/notification_channel.rb
112
114
  - lib/noticed/text_coder.rb
113
115
  - lib/noticed/translation.rb
114
116
  - lib/noticed/version.rb