missive 0.0.2 → 0.0.3

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: 63e8195762299f95bdc217efcf1a81dbd8be46ec029ea90b8b4db430af37eabd
4
- data.tar.gz: 94532fa3c3cd42c9086b35385773c0d2f8483dad96690b0d78523512736aa86e
3
+ metadata.gz: '06220491a9066084b07838222a15676c94543dcec8d6d7a9e3c84137e8efab14'
4
+ data.tar.gz: cd08afa7a073de913d16f3ffe6251c31c196696420a2f5ccd51d8c1d6bff48f0
5
5
  SHA512:
6
- metadata.gz: d365c0b22c19489e7d61d46746bec34d58834c167066f02eb71cec287e855a7e820e1eb535e066c2f871cc948338bbbd5151efac7838ca037e2455b36c4dbe07
7
- data.tar.gz: d7c9d72e65bbac0b683b6f5b69b888547f7ebc5245c35b6b9f582042ad8ef524b775acaed2aa47d17dd4a2be689315c02e41570913edebf7c213b5d0dc728f6f
6
+ metadata.gz: d32d340f9c5c473f320f3590339455b83408fc5854022bb4ad5888f59ee002a08cca4f8ec95bfec9b022d4557af3bad45554f44db137778c5337683c842cfbd2
7
+ data.tar.gz: d15612829c698aa1f4bfa5f2177033da4745a9f4d2b835972d24dea1023a186c7bfe6227b9b2fe61cdecc78cee62b955977089d7f57d775a0ab326063b992072
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.0.3] - 2026-02-04
4
+
5
+ - Add associations collision checks and configuration
6
+
7
+ ## [0.0.2] - 2025-12-14
8
+
3
9
  - Add install generator
4
10
  - Add Postmark Bulk API implementation
5
11
 
data/README.md CHANGED
@@ -113,6 +113,54 @@ class User < ApplicationRecord
113
113
  end
114
114
  ```
115
115
 
116
+ #### Customizing association names
117
+
118
+ If your User model already has associations named `sender` or `subscriber`, you can customize the association names:
119
+
120
+ ```rb
121
+ class User < ApplicationRecord
122
+ include Missive::User
123
+ configure_missive_sender(
124
+ sender: :missive_sender,
125
+ sent_dispatches: :missive_sent_dispatches,
126
+ sent_lists: :missive_sent_lists,
127
+ sent_messages: :missive_sent_messages
128
+ )
129
+ configure_missive_subscriber(
130
+ subscriber: :missive_subscriber,
131
+ dispatches: :missive_dispatches,
132
+ subscriptions: :missive_subscriptions,
133
+ subscribed_lists: :missive_subscribed_lists,
134
+ unsubscribed_lists: :missive_unsubscribed_lists
135
+ )
136
+ end
137
+ ```
138
+
139
+ Or, if including the concerns separately:
140
+
141
+ ```rb
142
+ class User < ApplicationRecord
143
+ include Missive::UserAsSender
144
+ configure_missive_sender(
145
+ sender: :missive_sender,
146
+ sent_dispatches: :missive_sent_dispatches,
147
+ sent_lists: :missive_sent_lists,
148
+ sent_messages: :missive_sent_messages
149
+ )
150
+
151
+ include Missive::UserAsSubscriber
152
+ configure_missive_subscriber(
153
+ subscriber: :missive_subscriber,
154
+ dispatches: :missive_dispatches,
155
+ subscriptions: :missive_subscriptions,
156
+ subscribed_lists: :missive_subscribed_lists,
157
+ unsubscribed_lists: :missive_unsubscribed_lists
158
+ )
159
+ end
160
+ ```
161
+
162
+ You only need to customize the associations that conflict - any unconfigured associations will use their default names.
163
+
116
164
  #### Manage subscriptions
117
165
 
118
166
  ```rb
@@ -2,17 +2,50 @@ module Missive
2
2
  module UserAsSender
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ class AssociationAlreadyDefinedError < StandardError; end
6
+
7
+ ASSOCIATION_NAMES = %i[sender sent_dispatches sent_lists sent_messages].freeze
8
+
9
+ class_methods do
10
+ def missive_sender_config
11
+ @missive_sender_config ||= ASSOCIATION_NAMES.index_with { |name| name }
12
+ end
13
+
14
+ def configure_missive_sender(options = {})
15
+ missive_sender_config.merge!(options)
16
+ _define_missive_sender_associations
17
+ end
18
+
19
+ def _define_missive_sender_associations
20
+ config = missive_sender_config
21
+
22
+ _check_missive_association_collision!(config[:sender])
23
+
24
+ has_one config[:sender], class_name: "Missive::Sender", foreign_key: :user_id, dependent: :nullify
25
+ has_many config[:sent_dispatches], class_name: "Missive::Dispatch", through: config[:sender], source: :dispatches
26
+ has_many config[:sent_lists], class_name: "Missive::List", through: config[:sender], source: :lists
27
+ has_many config[:sent_messages], class_name: "Missive::Message", through: config[:sender], source: :messages
28
+ end
29
+
30
+ def _check_missive_association_collision!(name)
31
+ return unless reflect_on_association(name)
32
+
33
+ raise AssociationAlreadyDefinedError,
34
+ "Association :#{name} is already defined on #{self.name}. " \
35
+ "Use configure_missive_sender to specify a different name. " \
36
+ "Example: configure_missive_sender(sender: :missive_sender)"
37
+ end
38
+ end
39
+
5
40
  included do
6
- has_one :sender, class_name: "Missive::Sender", dependent: :nullify
7
- has_many :sent_dispatches, class_name: "Missive::Dispatch", through: :sender, source: :dispatches
8
- has_many :sent_lists, class_name: "Missive::List", through: :sender, source: :lists
9
- has_many :sent_messages, class_name: "Missive::Message", through: :sender, source: :messages
41
+ _define_missive_sender_associations
10
42
 
11
43
  def init_sender(attributes = {})
12
- self.sender = Missive::Sender.find_or_initialize_by(email:)
13
- sender.assign_attributes(attributes)
14
- sender.save!
15
- sender
44
+ assoc = self.class.missive_sender_config[:sender]
45
+ send("#{assoc}=", Missive::Sender.find_or_initialize_by(email:))
46
+ send(assoc).assign_attributes(attributes)
47
+ send(assoc).save!
48
+ send(assoc)
16
49
  end
17
50
  end
18
51
  end
@@ -2,21 +2,54 @@ module Missive
2
2
  module UserAsSubscriber
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ class AssociationAlreadyDefinedError < StandardError; end
6
+
7
+ ASSOCIATION_NAMES = %i[subscriber dispatches subscriptions subscribed_lists unsubscribed_lists].freeze
8
+
9
+ class_methods do
10
+ def missive_subscriber_config
11
+ @missive_subscriber_config ||= ASSOCIATION_NAMES.index_with { |name| name }
12
+ end
13
+
14
+ def configure_missive_subscriber(options = {})
15
+ missive_subscriber_config.merge!(options)
16
+ _define_missive_subscriber_associations
17
+ end
18
+
19
+ def _define_missive_subscriber_associations
20
+ config = missive_subscriber_config
21
+
22
+ _check_missive_association_collision!(config[:subscriber])
23
+
24
+ has_one config[:subscriber], class_name: "Missive::Subscriber", foreign_key: :user_id, dependent: :destroy
25
+ has_many config[:dispatches], class_name: "Missive::Dispatch", through: config[:subscriber]
26
+ has_many config[:subscriptions], class_name: "Missive::Subscription", through: config[:subscriber]
27
+ has_many config[:subscribed_lists], class_name: "Missive::List", through: config[:subscriber], source: :lists
28
+ has_many config[:unsubscribed_lists], -> { where.not(missive_subscriptions: {suppressed_at: nil}) },
29
+ class_name: "Missive::List",
30
+ through: config[:subscriber],
31
+ source: :lists
32
+ end
33
+
34
+ def _check_missive_association_collision!(name)
35
+ return unless reflect_on_association(name)
36
+
37
+ raise AssociationAlreadyDefinedError,
38
+ "Association :#{name} is already defined on #{self.name}. " \
39
+ "Use configure_missive_subscriber to specify a different name. " \
40
+ "Example: configure_missive_subscriber(subscriber: :missive_subscriber)"
41
+ end
42
+ end
43
+
5
44
  included do
6
- has_one :subscriber, class_name: "Missive::Subscriber", dependent: :destroy
7
- has_many :dispatches, class_name: "Missive::Dispatch", through: :subscriber
8
- has_many :subscriptions, class_name: "Missive::Subscription", through: :subscriber
9
- has_many :subscribed_lists, class_name: "Missive::List", through: :subscriber, source: :lists
10
- has_many :unsubscribed_lists, -> { where.not(missive_subscriptions: {suppressed_at: nil}) },
11
- class_name: "Missive::List",
12
- through: :subscriber,
13
- source: :lists
45
+ _define_missive_subscriber_associations
14
46
 
15
47
  def init_subscriber(attributes = {})
16
- self.subscriber = Missive::Subscriber.find_or_initialize_by(email:)
17
- subscriber.assign_attributes(attributes)
18
- subscriber.save!
19
- subscriber
48
+ assoc = self.class.missive_subscriber_config[:subscriber]
49
+ send("#{assoc}=", Missive::Subscriber.find_or_initialize_by(email:))
50
+ send(assoc).assign_attributes(attributes)
51
+ send(assoc).save!
52
+ send(assoc)
20
53
  end
21
54
  end
22
55
  end
@@ -1,3 +1,3 @@
1
1
  module Missive
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: missive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hans Lemuet
@@ -130,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  requirements: []
133
- rubygems_version: 3.7.2
133
+ rubygems_version: 4.0.4
134
134
  specification_version: 4
135
135
  summary: Toolbox for managing newsletters in Rails, sending them with Postmark.
136
136
  test_files: []