heya 0.9.0 → 0.11.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: b8cc645db907bf986618b2ee1f6b21c33f55ad8d53c7f27f9c2dc1f7b05960dc
4
- data.tar.gz: 2aad3fdf5254ccbdd986161c517d6d2052e4d0ec85ab426aa940954a0d9a4008
3
+ metadata.gz: d8c3a56453c65b17eaa7dcc3489bacd9dcdb78da9f134e18e0fa7d3cc818de11
4
+ data.tar.gz: cd6eb4a27002ebb62307cd44007960cc39637f7ab6b3129d5800061e1bf762c4
5
5
  SHA512:
6
- metadata.gz: bcaa2e67bf73027e7d1c8cd813fe02d84a9bc53120c8cfbef9ecd5726537bd0a47fb93d0f711a4adff29c7a6f03592e1615d223c7cce3ee3fa944b008d600f8b
7
- data.tar.gz: f17a412448e15e95e392baedbe639300aa2f05d4288a65fae805932d2bb1494fad87586b6d13ee64e8ffee26a2e0b6957f530e7d6299797edf464d42f9a5e809
6
+ metadata.gz: 69aacf834f7a3d02e63aff2dc4be5af386785e2c5172c19dadedb6789c1557332efbbc33db3a2be75382a05f0b746c7c1787fd369bbbc081e655c137006905df
7
+ data.tar.gz: 2d3c1465261ba7b1737aa64e20b00e14f696f401f1abe1a93e31ec3fd6b5133d7f4fc6cee886a817e478a43ca3ae4ec5ba9760a4e62a685f6db9568acddab0b9
data/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
+ ### Added
9
+ - Support Rails 7.2 (#270, @jbennett)
10
+
11
+ ### Fixed
12
+ - Fix a typo in message.html.erb.tt.
13
+
14
+ ## [0.10.0] - 2024-03-18
15
+ ### Added
16
+ - Add lambda support for from, bcc, and reply_to campaign options (#233, @armiiller)
17
+
18
+ ### Fixed
19
+ - Fix a Rails startup bug when validating steps that use translations from locale
20
+ files. (#211)
21
+
22
+ ## [0.9.0] - 2023-10-06
23
+ ### Added
8
24
  - Rails 7.1 support
9
25
 
10
26
  ## [0.8.0] - 2023-03-28
data/README.md CHANGED
@@ -1,72 +1,89 @@
1
1
  # Heya 👋
2
+
2
3
  ![Test](https://github.com/honeybadger-io/heya/workflows/Test/badge.svg)
3
4
  [![Gem Version](https://badge.fury.io/rb/heya.svg)](https://badge.fury.io/rb/heya)
4
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/a6416e63ffc426715857/maintainability)](https://codeclimate.com/github/honeybadger-io/heya/maintainability)
5
6
 
6
- Heya is a campaign mailer for Rails. Think of it like ActionMailer, but for timed email sequences. It can also perform other actions like sending a text message.
7
+ Heya is a campaign mailer for Rails. Think of it like ActionMailer, but for
8
+ timed email sequences. It can also perform other actions like sending a text
9
+ message.
7
10
 
8
11
  ## Getting started
12
+
9
13
  Getting started with Heya is easy:
10
14
 
11
15
  1. [Install the gem](#installing-the-heya-gem)
12
16
  2. [Create a campaign](#creating-your-first-campaign)
13
17
  3. [Run the scheduler](#running-the-scheduler)
14
18
 
19
+ ### Prerequisites
20
+
21
+ Heya was built to work with PostgreSQL. Pull requests are welcome to support
22
+ more databases.
23
+
15
24
  ### Installing the Heya gem
25
+
16
26
  1. Add this line to your application's Gemfile:
17
27
 
18
- ```ruby
19
- gem "heya", github: "honeybadger-io/heya"
20
- ```
28
+ ```ruby
29
+ gem "heya", github: "honeybadger-io/heya"
30
+ ```
21
31
 
22
32
  2. Then execute:
23
33
 
24
- ```bash
25
- bundle install
26
- rails generate heya:install
27
- rails db:migrate
28
- ```
34
+ ```bash
35
+ bundle install
36
+ rails generate heya:install
37
+ rails db:migrate
38
+ ```
29
39
 
30
- This will:
40
+ This will:
31
41
 
32
- 1. Copy Heya's migration files to *db/migrate*
33
- 1. Copy Heya's default initializer to *config/initializers/heya.rb*
34
- 1. Create the file *app/campaigns/application_campaign.rb*
35
- 1. Run local migrations
42
+ 1. Copy Heya's migration files to _db/migrate_
43
+ 1. Copy Heya's default initializer to _config/initializers/heya.rb_
44
+ 1. Create the file _app/campaigns/application_campaign.rb_
45
+ 1. Run local migrations
36
46
 
37
- <details><summary>Note: Heya doesn't store a copy of your user data; instead, it reads from your existing <code>User</code> model (it never writes). If you have a different user model, change the <code>user_type</code> configuration option in <em>config/initializers/heya.rb</em>.</summary>
47
+ <details>
48
+ <summary>Note: Heya doesn't store a copy of your user data; instead, it
49
+ reads from your existing <code>User</code> model (it never writes). If you
50
+ have a different user model, change the <code>user_type</code> configuration
51
+ option in <em>config/initializers/heya.rb</em>.</summary>
38
52
 
39
53
  ```ruby
40
54
  # config/initializers/heya.rb
41
55
  Heya.configure do |config|
42
- config.user_type = "MyUser"
56
+ config.user_type = "MyUser"
43
57
  end
44
58
  ```
59
+
45
60
  </details>
46
61
 
47
62
  ### Creating your first campaign
63
+
48
64
  1. Create a campaign:
49
65
 
50
- ```bash
51
- rails generate heya:campaign Onboarding welcome:0
52
- ```
66
+ ```bash
67
+ rails generate heya:campaign Onboarding welcome:0
68
+ ```
53
69
 
54
70
  2. Add a user to your campaign:
55
71
 
56
- ```ruby
57
- OnboardingCampaign.add(user)
58
- ```
72
+ ```ruby
73
+ OnboardingCampaign.add(user)
74
+ ```
59
75
 
60
- Add the following to your `User` model to send them the campaign
61
- when they first signup:
76
+ Add the following to your `User` model to send them the campaign
77
+ when they first sign up:
62
78
 
63
- ```ruby
64
- after_create_commit do
65
- OnboardingCampaign.add(self)
66
- end
67
- ```
79
+ ```ruby
80
+ after_create_commit do
81
+ OnboardingCampaign.add(self)
82
+ end
83
+ ```
68
84
 
69
85
  ### Running the scheduler
86
+
70
87
  To start queuing emails, run the scheduler task periodically:
71
88
 
72
89
  ```bash
@@ -92,7 +109,9 @@ end
92
109
 
93
110
  ### Bonus: tips for working with email in Rails
94
111
 
95
- <details><summary>Use <a href="http://mailcatcher.me">MailCatcher</a> to see emails sent from your dev environment</summary>
112
+ <details>
113
+ <summary>Use <a href="http://mailcatcher.me">MailCatcher</a> to see
114
+ emails sent from your dev environment</summary>
96
115
 
97
116
  ```ruby
98
117
  # config/environments/development.rb
@@ -111,8 +130,11 @@ Rails.application.configure do
111
130
  config.action_mailer.smtp_settings = {host: "localhost", port: 1025}
112
131
  end
113
132
  ```
133
+
114
134
  </details>
115
- <details><summary>Use <a href="https://github.com/codetriage/maildown">Maildown</a> to write your emails in Markdown</summary>
135
+ <details>
136
+ <summary>Use <a href="https://github.com/codetriage/maildown">Maildown</a> to
137
+ write your emails in Markdown</summary>
116
138
 
117
139
  ```sh
118
140
  $ bundle add maildown
@@ -124,12 +146,16 @@ $ rails generate heya:campaign Onboarding welcome
124
146
 
125
147
  ☝️ Notice how only one template was generated; Maildown automatically builds
126
148
  the HTML and text variants from the markdown file.
149
+
127
150
  </details>
128
- <details><summary>Use <a href="https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails">ActionMailer::Preview</a> to preview emails as you write them</summary>
151
+ <details>
152
+ <summary>Use <a
153
+ href="https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails">ActionMailer::Preview</a>
154
+ to preview emails as you write them</summary>
129
155
 
130
156
  Heya's campaign generator generates previews for campaigns at
131
157
  `(test|spec)/mailers/previews/*_campaign_preview.rb`. To see them, open
132
- http://localhost:3000/rails/mailers/. If you didn't use the generator, you
158
+ <http://localhost:3000/rails/mailers/>. If you didn't use the generator, you
133
159
  can still build your own preview:
134
160
 
135
161
  ```ruby
@@ -147,12 +173,13 @@ class OnboardingCampaignPreview < ActionMailer::Preview
147
173
  end
148
174
 
149
175
  ```
176
+
150
177
  </details>
151
178
 
152
179
  ## Configuration
153
180
 
154
181
  You can use the following options to configure Heya (find this file in
155
- *config/initializers/heya.rb*):
182
+ _config/initializers/heya.rb_):
156
183
 
157
184
  ```ruby
158
185
  Heya.configure do |config|
@@ -176,7 +203,10 @@ end
176
203
  ## Campaigns
177
204
 
178
205
  ### Creating campaigns
179
- Heya stores campaigns in *app/campaigns/*, similar to how Rails stores mailers in *app/mailers/*. To create a campaign, run the following command inside your Rails project:
206
+
207
+ Heya stores campaigns in _app/campaigns/_, similar to how Rails stores mailers
208
+ in _app/mailers/_. To create a campaign, run the following command inside your
209
+ Rails project:
180
210
 
181
211
  ```bash
182
212
  rails generate heya:campaign Onboarding first second third
@@ -184,10 +214,10 @@ rails generate heya:campaign Onboarding first second third
184
214
 
185
215
  This will:
186
216
 
187
- 1. Create the file *app/campaigns/onboarding_campaign.rb*
188
- 1. Create the directory *app/views/heya/campaign_mailer/onboarding_campaign/*
189
- 1. Create email templates inside of *app/views/heya/campaign_mailer/onboarding_campaign/*
190
- 1. Create an ActionMailer preview at *(test|spec)/mailers/previews/onboarding_campaign_preview.rb*
217
+ 1. Create the file _app/campaigns/onboarding_campaign.rb_
218
+ 1. Create the directory _app/views/heya/campaign_mailer/onboarding_campaign/_
219
+ 1. Create email templates inside of _app/views/heya/campaign_mailer/onboarding_campaign/_
220
+ 1. Create an ActionMailer preview at _(test|spec)/mailers/previews/onboarding_campaign_preview.rb_
191
221
 
192
222
  Here's the campaign that the above command generates:
193
223
 
@@ -211,16 +241,26 @@ end
211
241
  ```
212
242
 
213
243
  #### Steps
214
- The `step` method defines a new step in the sequence. When you add a user to the campaign, Heya completes each step in the order that it appears.
215
244
 
216
- The default time to wait between steps is *two days*, calculated from the time the user completed the previous step (or the time the user entered the campaign, in the case of the first step).
245
+ The `step` method defines a new step in the sequence. When you add a user to the
246
+ campaign, Heya completes each step in the order that it appears.
247
+
248
+ The default time to wait between steps is _two days_, calculated from the time
249
+ the user completed the previous step (or the time the user entered the campaign,
250
+ in the case of the first step).
217
251
 
218
- Each step has several options available (see the section [Creating messages](#creating-messages)).
252
+ Each step has several options available (see the section [Creating
253
+ messages](#creating-messages)).
219
254
 
220
255
  ### Creating messages
221
- Messages are defined inside Heya campaigns using the `step` method. When you add a user to a campaign, Heya completes each step in the order that it appears.
222
256
 
223
- **The most important part of each step is its name, which must be unique to the campaign.** The step's name is how Heya tracks which user has received which message, so it's essential that you don't change it after the campaign is active (if you do, Heya will assume it's a new message).
257
+ Messages are defined inside Heya campaigns using the `step` method. When you add
258
+ a user to a campaign, Heya completes each step in the order that it appears.
259
+
260
+ **The most important part of each step is its name, which must be unique to the
261
+ campaign.** The step's name is how Heya tracks which user has received which
262
+ message, so it's essential that you don't change it after the campaign is active
263
+ (if you do, Heya will assume it's a new message).
224
264
 
225
265
  Here's an example of defining a message inside a campaign:
226
266
 
@@ -231,9 +271,12 @@ class OnboardingCampaign < ApplicationCampaign
231
271
  end
232
272
  ```
233
273
 
234
- In the above example, Heya will send a message named `:welcome` one day after a user enters the campaign, with the subject "Welcome to my app!"
274
+ In the above example, Heya will send a message named `:welcome` one day after a
275
+ user enters the campaign, with the subject "Welcome to my app!"
235
276
 
236
- The `wait` option tells Heya how long to wait before sending each message (the default is two days). There are a few scheduling options that you can customize for each step:
277
+ The `wait` option tells Heya how long to wait before sending each message (the
278
+ default is two days). There are a few scheduling options that you can customize
279
+ for each step:
237
280
 
238
281
  | Option Name | Default | Description |
239
282
  | :---------- | :-------------------------------- | :------------------------------------------------------- |
@@ -244,16 +287,18 @@ The `wait` option tells Heya how long to wait before sending each message (the d
244
287
 
245
288
  Heya uses the following additional options to build the message itself:
246
289
 
247
- | Option Name | Default | Description |
248
- |-------------|--------------|----------------------------|
249
- | `subject` | **required** | The email's subject |
250
- | `from` | Heya default | The sender's email address |
251
- | `layout` | Heya default | The email's layout file |
252
- | `to` | See below | The recipient's name & email address |
253
- | `bcc` | `nil` | BCC when sending emails |
290
+ | Option Name | Default | Description |
291
+ | ----------- | ------------ | -------------------------------------- |
292
+ | `subject` | **required** | The email's subject |
293
+ | `from` | Heya default | The sender's email address |
294
+ | `layout` | Heya default | The email's layout file |
295
+ | `to` | See below | The recipient's name & email address |
296
+ | `bcc` | `nil` | BCC when sending emails |
254
297
  | `headers` | `{}` | Headers to include when sending emails |
255
298
 
256
- You can change the default options using the `default` method at the top of the campaign. Heya applies default options to each step which doesn't supply its own:
299
+ You can change the default options using the `default` method at the top of the
300
+ campaign. Heya applies default options to each step which doesn't supply its
301
+ own:
257
302
 
258
303
  ```ruby
259
304
  class OnboardingCampaign < ApplicationCampaign
@@ -271,7 +316,8 @@ end
271
316
 
272
317
  #### Customizing the `to` field
273
318
 
274
- You can customize the `to` field by passing a callable object, which Heya will invoke with the user. For instance:
319
+ You can customize the `to` field by passing a callable object, which Heya will
320
+ invoke with the user. For instance:
275
321
 
276
322
  ```ruby
277
323
  class OnboardingCampaign < ApplicationCampaign
@@ -281,19 +327,23 @@ class OnboardingCampaign < ApplicationCampaign
281
327
  end
282
328
  ```
283
329
 
284
- It is recommended to rely on `ActionMailer::Base.email_address_with_name` so that sanitization is correctly applied.
330
+ It is recommended to rely on `ActionMailer::Base.email_address_with_name` so
331
+ that sanitization is correctly applied.
285
332
 
286
333
  If the `to` param is not provided, Heya will default to:
287
334
 
288
335
  1. `user#first_name`
289
336
  1. `user#name`
290
337
 
291
- If the `user` object doesn't respond to these methods, it will fallback to a simple `user.email` in the `to` field.
338
+ If the `user` object doesn't respond to these methods, it will fallback to a
339
+ simple `user.email` in the `to` field.
292
340
 
293
341
  #### Quality control option
294
342
 
295
- You may wish to apply quality control to individual steps of a campaign. For example, when adding a new step to an existing campaign it is
296
- a good idea to inspect real-time results in production. You can do this by using the `bcc:` step option, which would look like this:
343
+ You may wish to apply quality control to individual steps of a campaign. For
344
+ example, when adding a new step to an existing campaign it is a good idea to
345
+ inspect real-time results in production. You can do this by using the `bcc:`
346
+ step option, which would look like this:
297
347
 
298
348
  ```ruby
299
349
  class OnboardingCampaign < ApplicationCampaign
@@ -326,7 +376,9 @@ end
326
376
 
327
377
  #### Translations for email subjects (I18n)
328
378
 
329
- If you don't pass a `subject` to the `step` method, Heya will try to find it in your translations. The performed lookup will use the pattern `<campaign_scope>.<step_name>.subject` to construct the key.
379
+ If you don't pass a `subject` to the `step` method, Heya will try to find it in
380
+ your translations. The performed lookup will use the pattern
381
+ `<campaign_scope>.<step_name>.subject` to construct the key.
330
382
 
331
383
  ```ruby
332
384
  # app/campaigns/onboarding_campaign.rb
@@ -343,7 +395,8 @@ en:
343
395
  subject: "Heya!"
344
396
  ```
345
397
 
346
- To define parameters for interpolation, define a `#heya_attributes` method on your user model:
398
+ To define parameters for interpolation, define a `#heya_attributes` method on
399
+ your user model:
347
400
 
348
401
  ```ruby
349
402
  # app/models/user.rb
@@ -387,7 +440,9 @@ Step blocks receive two optional arguments: `user` and `step`, and are processed
387
440
  in a background job alongside other actions.
388
441
 
389
442
  ### Adding users to campaigns
390
- Heya leaves *when* to add users to campaigns completely up to you; here's how to add a user to a campaign from anywhere in your app:
443
+
444
+ Heya leaves _when_ to add users to campaigns completely up to you; here's how to
445
+ add a user to a campaign from anywhere in your app:
391
446
 
392
447
  ```ruby
393
448
  OnboardingCampaign.add(user)
@@ -399,24 +454,33 @@ To remove a user from a campaign:
399
454
  OnboardingCampaign.remove(user)
400
455
  ```
401
456
 
402
- Adding users to campaigns from Rails opens up some interesting automation possibilities--for instance, you can start or stop campaigns from `ActiveRecord` callbacks, or in response to other events that you're already tracking in your application. [See here for a list of ideas](#automation-ideas).
457
+ Adding users to campaigns from Rails opens up some interesting automation
458
+ possibilities--for instance, you can start or stop campaigns from `ActiveRecord`
459
+ callbacks, or in response to other events that you're already tracking in your
460
+ application. [See here for a list of ideas](#automation-ideas).
403
461
 
404
- Because Heya stacks campaigns by default (meaning it will never send more than one at a time), you can also queue up several campaigns for a user, and they'll receive them in order:
462
+ Because Heya stacks campaigns by default (meaning it will never send more than
463
+ one at a time), you can also queue up several campaigns for a user, and they'll
464
+ receive them in order:
405
465
 
406
466
  ```ruby
407
467
  WelcomeCampaign.add(user)
408
468
  OnboardingCampaign.add(user)
409
469
  EvergreenCampaign.add(user)
410
470
  ```
411
- *Note: you can customize the priority of campaigns via Heya's configuration.*
412
471
 
413
- If you want to send a user two campaigns simultaneously, you can do so with the `concurrent` option:
472
+ _Note: you can customize the priority of campaigns via Heya's configuration._
473
+
474
+ If you want to send a user two campaigns simultaneously, you can do so with the
475
+ `concurrent` option:
414
476
 
415
477
  ```ruby
416
478
  FlashSaleCampaign.add(user, concurrent: true)
417
479
  ```
418
480
 
419
- When you remove a user from a campaign and add them back later, they'll continue where they left off. If you want them to start over from the beginning, use the `restart` option:
481
+ When you remove a user from a campaign and add them back later, they'll continue
482
+ where they left off. If you want them to start over from the beginning, use the
483
+ `restart` option:
420
484
 
421
485
  ```ruby
422
486
  TrialConversionCampaign.add(user, restart: true)
@@ -424,7 +488,8 @@ TrialConversionCampaign.add(user, restart: true)
424
488
 
425
489
  #### Automation ideas
426
490
 
427
- Using `ActiveSupport::Notifications` to respond to lifecycle events (which could be sent from your Stripe controller, for instance):
491
+ Using `ActiveSupport::Notifications` to respond to lifecycle events (which could
492
+ be sent from your Stripe controller, for instance):
428
493
 
429
494
  ```ruby
430
495
  ActiveSupport::Notifications.subscribe("user.trial_will_end") do |*args|
@@ -449,7 +514,10 @@ end
449
514
  ```
450
515
 
451
516
  ### Customizing who gets what
452
- Heya can send individual messages to certain users using the `segment` option. The following campaign will send the message to inactive users--active users will be skipped:
517
+
518
+ Heya can send individual messages to certain users using the `segment` option.
519
+ The following campaign will send the message to inactive users--active users
520
+ will be skipped:
453
521
 
454
522
  ```ruby
455
523
  class ActivationCampaign < ApplicationCampaign
@@ -457,7 +525,8 @@ class ActivationCampaign < ApplicationCampaign
457
525
  end
458
526
  ```
459
527
 
460
- When you're checking the value of a single method on the user, the segment can be simplified to the symbol version:
528
+ When you're checking the value of a single method on the user, the segment can
529
+ be simplified to the symbol version:
461
530
 
462
531
  ```ruby
463
532
  class ActivationCampaign < ApplicationCampaign
@@ -466,7 +535,11 @@ end
466
535
  ```
467
536
 
468
537
  #### Segmenting specific campaigns
469
- You can also narrow entire campaigns to certain users using the `segment` method. For instance, if you have a campaign with a specific goal such as performing an action in your app, then you can send the campaign only to the users who haven't performed the action:
538
+
539
+ You can also narrow entire campaigns to certain users using the `segment`
540
+ method. For instance, if you have a campaign with a specific goal such as
541
+ performing an action in your app, then you can send the campaign only to the
542
+ users who haven't performed the action:
470
543
 
471
544
  ```ruby
472
545
  class UpgradeCampaign < ApplicationCampaign
@@ -478,9 +551,12 @@ class UpgradeCampaign < ApplicationCampaign
478
551
  end
479
552
  ```
480
553
 
481
- If they upgrade half way through the campaign, Heya will stop sending messages and remove them from the campaign.
554
+ If they upgrade half way through the campaign, Heya will stop sending messages
555
+ and remove them from the campaign.
482
556
 
483
- Likewise, you can require that users meet conditions to continue receiving a campaign. Here's a campaign which sends messages only to trial users--non-trial users will be removed from the campaign:
557
+ Likewise, you can require that users meet conditions to continue receiving a
558
+ campaign. Here's a campaign which sends messages only to trial users--non-trial
559
+ users will be removed from the campaign:
484
560
 
485
561
  ```ruby
486
562
  class TrialCampaign < ApplicationCampaign
@@ -493,6 +569,7 @@ end
493
569
  ```
494
570
 
495
571
  #### Segmenting all campaigns
572
+
496
573
  Heya campaigns inherit options from parent campaigns. For example, to make sure
497
574
  unsubscribed users never receive an email from Heya, create a `segment` in the
498
575
  `ApplicationCampaign`, and then have all other campaigns inherit from it:
@@ -524,72 +601,169 @@ See the
524
601
  [Rails documentation](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html#method-i-rescue_from)
525
602
  for additional details.
526
603
 
604
+ ### Extending campaign mailers
605
+
606
+ The campaign generator does not create a Mailer class for campaigns. In order to
607
+ enhance a campaign with a macro from another gem (such as for adding analytics),
608
+ you can do so by extending the `Heya::ApplicationMailer` class.
609
+
610
+ 1. Create a new file at `app/mailers/heya/application_mailer.rb`
611
+ 2. Add the following to it:
612
+
613
+ ```ruby
614
+ module Heya
615
+ class ApplicationMailer < ActionMailer::Base
616
+ macro_to_add_to_all_campaign_mailers
617
+ end
618
+ end
619
+ ```
620
+
621
+ For example, here's how to extended `Heya::ApplicationMailer` to include [Ahoy
622
+ Email's](https://github.com/ankane/ahoy_email)
623
+ [has_history](https://github.com/ankane/ahoy_email?tab=readme-ov-file#message-history)
624
+ and
625
+ [track_clicks](https://github.com/ankane/ahoy_email?tab=readme-ov-file#usage)
626
+ macros:
627
+
628
+ ```ruby
629
+ # app/mailers/heya/application_mailer.rb
630
+
631
+ module Heya
632
+ class ApplicationMailer < ActionMailer::Base
633
+ has_history
634
+
635
+ track_clicks campaign: -> {
636
+ params[:step].campaign.name
637
+ }
638
+ end
639
+ end
640
+ ```
641
+
642
+ This does two things:
643
+
644
+ 1. `has_history` enables history tracking for all Heya emails
645
+ 2. The `track_clicks` block appends the name of the campaign to all
646
+ (non-unsubscribe) links in an email so that each campaign can keep its data
647
+ separate from the other campaigns.
648
+
649
+ The result of this is that you can run a command like this in the console:
650
+
651
+ ```irb
652
+ AhoyEmail.stats "OnboardingCampaign"
653
+ ```
654
+
655
+ ...and receive a result:
656
+
657
+ ```irb
658
+ => {:sends=>1, :clicks=>2, :unique_clicks=>1, :ctr=>100.0}
659
+ ```
660
+
527
661
  ### Campaigns FAQ
662
+
528
663
  **What happens when:**
664
+
529
665
  <details><summary>I reorder messages in an active campaign?</summary>
530
666
 
531
- Heya sends the next *unsent* message *after the last message the user received*. When you move a message, the users who last received it will be moved with it, and continue from that point in the campaign. Heya skips messages which the user has already seen.
667
+ Heya sends the next _unsent_ message _after the last message the user received_.
668
+ When you move a message, the users who last received it will be moved with it,
669
+ and continue from that point in the campaign. Heya skips messages which the user
670
+ has already seen.
671
+
532
672
  </details>
533
673
 
534
674
  <details><summary>I add a message to an active campaign?</summary>
535
675
 
536
- Users who have already received a message *after* the new message will *not* receive the message.
676
+ Users who have already received a message _after_ the new message will _not_
677
+ receive the message.
678
+
537
679
  </details>
538
680
 
539
681
  <details><summary>I remove a message from an active campaign?</summary>
540
682
 
541
- Users who last received the message will be moved up to the previously received message, and continue from that point in the campaign. Heya skips messages which the user has already seen.
683
+ Users who last received the message will be moved up to the previously received
684
+ message, and continue from that point in the campaign. Heya skips messages which
685
+ the user has already seen.
686
+
542
687
  </details>
543
688
 
544
689
  <details><summary>I rename a message in an active campaign?</summary>
545
690
 
546
- **Renaming a message is equivalent to removing the message and adding a new one.** Users who are waiting to receive an earlier message in the campaign will receive the new message. Users who last received the old message will also receive the new one since it has replaced its position in the campaign.
691
+ **Renaming a message is equivalent to removing the message and adding a new
692
+ one.** Users who are waiting to receive an earlier message in the campaign will
693
+ receive the new message. Users who last received the old message will also
694
+ receive the new one since it has replaced its position in the campaign.
695
+
547
696
  </details>
548
697
 
549
698
  <details><summary>A user skips a message based on its conditions?</summary>
550
699
 
551
- Heya waits the defined wait time for every message in the campaign. If a user doesn't match the conditions, Heya skips it. If the *next* message's wait time is less than or equal to the skipped message's, it sends it immediately. If the next wait period is longer, it sends it after the new wait time has elapsed.
700
+ Heya waits the defined wait time for every message in the campaign. If a user
701
+ doesn't match the conditions, Heya skips it. If the _next_ message's wait time
702
+ is less than or equal to the skipped message's, it sends it immediately. If the
703
+ next wait period is longer, it sends it after the new wait time has elapsed.
704
+
552
705
  </details>
553
706
 
554
707
  <details><summary>I delete an active campaign?</summary>
555
708
 
556
- Heya will immediately stop sending the campaign; the campaign's data will remain until you manually delete it. If you restore the file before deleting the campaign's data, Heya will resume sending the campaign.
709
+ Heya will immediately stop sending the campaign; the campaign's data will remain
710
+ until you manually delete it. If you restore the file before deleting the
711
+ campaign's data, Heya will resume sending the campaign.
712
+
557
713
  </details>
558
714
 
559
715
  <details><summary>I add a user to multiple campaigns?</summary>
560
716
 
561
- By default, Heya sends each user one campaign at a time. It determines the order of campaigns using the campaign `priority`. When you add a user to a higher priority campaign, the new campaign will begin immediately. Once completed, the next highest priority campaign will resume sending.
717
+ By default, Heya sends each user one campaign at a time. It determines the order
718
+ of campaigns using the campaign `priority`. When you add a user to a higher
719
+ priority campaign, the new campaign will begin immediately. Once completed, the
720
+ next highest priority campaign will resume sending.
562
721
 
563
722
  To send a campaign concurrent to other active campaigns, use the `concurrent` option.
723
+
564
724
  </details>
565
725
 
566
726
  <details><summary>I add a user to a campaign they already completed?</summary>
567
727
 
568
- When you add a user to a campaign that they previously completed, Heya sends new messages which were added *to the end of the campaign*. Skipped messages will *not* be sent. To resend all messages, use the `restart` option.
728
+ When you add a user to a campaign that they previously completed, Heya sends new
729
+ messages which were added _to the end of the campaign_. Skipped messages will
730
+ _not_ be sent. To resend all messages, use the `restart` option.
731
+
569
732
  </details>
570
733
 
571
734
  **Less frequently asked questions:**
735
+
572
736
  <details><summary>Can the same message be delivered twice?</summary>
573
737
 
574
- Nope, not without restarting the campaign using the `restart` option (which will resend all the messages).
738
+ Nope, not without restarting the campaign using the `restart` option (which will
739
+ resend all the messages).
740
+
575
741
  </details>
576
742
 
577
743
  <details><summary>Can the same campaign be sent twice?</summary>
578
744
 
579
- Yep. When you add a user to a campaign that they previously completed, Heya sends new messages which were added *to the end of the campaign*. Skipped messages will *not* be sent. To resend all messages, use the `restart` option.
745
+ Yep. When you add a user to a campaign that they previously completed, Heya
746
+ sends new messages which were added _to the end of the campaign_. Skipped
747
+ messages will _not_ be sent. To resend all messages, use the `restart` option.
748
+
580
749
  </details>
581
750
 
582
751
  <details><summary>Can I resend a campaign to a user?</summary>
583
752
 
584
- Yep. Use the `restart` option to resend a campaign to a user (if they are already in the campaign, the campaign will start over from the beginning).
753
+ Yep. Use the `restart` option to resend a campaign to a user (if they are
754
+ already in the campaign, the campaign will start over from the beginning).
755
+
585
756
  </details>
586
757
 
587
758
  <details><summary>Can I send a user two campaigns at the same time?</summary>
588
759
 
589
- Yep. By default, Heya sends campaigns ain order of `priority`. Use the `concurrent` option to send campaigns concurrently.
760
+ Yep. By default, Heya sends campaigns ain order of `priority`. Use the
761
+ `concurrent` option to send campaigns concurrently.
762
+
590
763
  </details>
591
764
 
592
765
  ## Upgrading Heya
766
+
593
767
  Heya adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and
594
768
  should be considered **unstable** until version 1.0.0. Always check
595
769
  [CHANGELOG.md](./CHANGELOG.md) prior to upgrading (breaking changes will always
@@ -597,18 +771,21 @@ be called out there). Upgrade instructions for breaking changes are in
597
771
  [UPGRADING.md](./UPGRADING.md).
598
772
 
599
773
  ## Roadmap
774
+
600
775
  See [here](https://github.com/honeybadger-io/heya/projects/1) for things we're
601
776
  considering adding to Heya.
602
777
 
603
778
  ## Contributing
779
+
604
780
  1. Fork it.
605
781
  2. Create a topic branch `git checkout -b my_branch`
606
- 3. Make your changes and add an entry to [CHANGELOG.md](CHANGELOG.md).
782
+ 3. Make your changes and add an entry to [CHANGELOG.md](./CHANGELOG.md).
607
783
  4. Commit your changes `git commit -am "Boom"`
608
784
  5. Push to your branch `git push origin my_branch`
609
785
  6. Send a [pull request](https://github.com/honeybadger-io/heya/pulls)
610
786
 
611
787
  ## Releasing
788
+
612
789
  1. `gem install gem-release`
613
790
  2. `gem bump -v [version] -t -r`
614
791
  3. Update unreleased heading in [CHANGELOG.md](./CHANGELOG.md) (TODO: automate
@@ -616,4 +793,5 @@ considering adding to Heya.
616
793
  4. `git push origin main --tags`
617
794
 
618
795
  ## License
796
+
619
797
  Heya is licensed under the [LGPL](./LICENSE).
@@ -12,8 +12,13 @@ module Heya
12
12
  step_name = step.name.underscore
13
13
 
14
14
  from = step.params.fetch("from")
15
+ from = from.call(user) if from.respond_to?(:call)
16
+
15
17
  bcc = step.params.fetch("bcc", nil)
18
+ bcc = bcc.call(user) if bcc.respond_to?(:call)
19
+
16
20
  reply_to = step.params.fetch("reply_to", nil)
21
+ reply_to = reply_to.call(user) if reply_to.respond_to?(:call)
17
22
 
18
23
  subject = step.params.fetch("subject") {
19
24
  I18n.t("#{campaign_name}.#{step_name}.subject", **attributes_for(user))
@@ -50,18 +50,9 @@ module Heya
50
50
  }
51
51
 
52
52
  scope :to_process, ->(now: Time.now, user: nil) {
53
- upcoming
54
- .where(<<~SQL, now: now.utc, user_type: user&.class&.base_class&.name, user_id: user&.id)
55
- ("heya_campaign_memberships".last_sent_at <= (TIMESTAMP :now - make_interval(secs := "heya_steps".wait)))
56
- AND (
57
- (:user_type IS NULL OR :user_id IS NULL)
58
- OR (
59
- "heya_campaign_memberships".user_type = :user_type
60
- AND
61
- "heya_campaign_memberships".user_id = :user_id
62
- )
63
- )
64
- SQL
53
+ query = upcoming.where('heya_campaign_memberships.last_sent_at <= (:now::timestamp - make_interval(secs := "heya_steps".wait))', now: now.utc)
54
+ query = query.where(user: user) if user
55
+ query
65
56
  }
66
57
 
67
58
  def self.migrate_next_step!
@@ -1 +1 @@
1
- This is the <%= @step.downcase %> messsage.
1
+ This is the <%= @step.downcase %> message.
@@ -1 +1 @@
1
- This is the <%= @step.downcase %> messsage.
1
+ This is the <%= @step.downcase %> message.
@@ -1 +1 @@
1
- This is the <%= @step.downcase %> messsage.
1
+ This is the <%= @step.downcase %> message.
@@ -6,8 +6,8 @@ module Heya
6
6
  module ActiveRecordRelationExtension
7
7
  TABLE_REGEXP = /heya_steps/
8
8
 
9
- def build_arel(aliases = nil)
10
- arel = super(aliases)
9
+ def build_arel(...) # forward all params. Handles differences between 7.1 -> 7.2
10
+ arel = super(...)
11
11
 
12
12
  if table_name == "heya_campaign_memberships" && arel.to_sql =~ TABLE_REGEXP
13
13
  # https://www.postgresql.org/docs/9.4/queries-values.html
data/lib/heya/engine.rb CHANGED
@@ -11,6 +11,18 @@ module Heya
11
11
  end
12
12
 
13
13
  config.to_prepare do
14
+ # This runs the first time *before* Rails is initialized. Because
15
+ # campaigns depend on Rails initialization, we use the `after_initialize`
16
+ # hook when Rails first starts up, and then `to_prepare` when reloading
17
+ # in development. See https://github.com/honeybadger-io/heya/issues/211
18
+ if ::Rails.application.initialized?
19
+ Dir.glob(Rails.root + "app/campaigns/*.rb").each do |c|
20
+ require_dependency(c)
21
+ end
22
+ end
23
+ end
24
+
25
+ config.after_initialize do
14
26
  Dir.glob(Rails.root + "app/campaigns/*.rb").each do |c|
15
27
  require_dependency(c)
16
28
  end
data/lib/heya/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Heya
4
- VERSION = "0.9.0"
4
+ VERSION = "0.11.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heya
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Wood
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-06 00:00:00.000000000 Z
11
+ date: 2024-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails