unsubscribe 0.1.0 → 1.0.0.alpha.1
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 +4 -4
- data/README.md +113 -8
- data/Rakefile +2 -2
- data/app/assets/stylesheets/unsubscribe/mailer_subscriptions.css +4 -0
- data/app/controllers/unsubscribe/mailer_subscriptions_controller.rb +66 -0
- data/app/helpers/unsubscribe/mailer_subscriptions_helper.rb +4 -0
- data/app/mailers/unsubscribe/application_mailer.rb +2 -2
- data/app/models/unsubscribe/mailer_subscription.rb +45 -0
- data/app/views/unsubscribe/mailer_subscriptions/show.html.erb +26 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20210918092925_create_unsubscribe_mailer_subscriptions.rb +15 -0
- data/lib/generators/unsubscribe/install/install_generator.rb +25 -0
- data/lib/generators/unsubscribe/views/views_generator.rb +13 -0
- data/lib/unsubscribe/error.rb +4 -0
- data/lib/unsubscribe/mailer.rb +41 -0
- data/lib/unsubscribe/owner.rb +21 -0
- data/lib/unsubscribe/version.rb +1 -1
- data/lib/unsubscribe.rb +4 -1
- metadata +18 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28f28f3bede2e59008c148b3262c718e621613bff193fcf8f22b0a6ad5302a50
|
4
|
+
data.tar.gz: 37b067207a3ed305fda44ca609f78e7d4307d10914ca2c2683f6df87bb978f43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5881a6787fd24d5860a433a93094addf13a143b71b4784a08dfaa1700432ddcbf2e2237351d573cb0030ec472ed49d41242a7fd2d67c73bb309905d4a49c06d
|
7
|
+
data.tar.gz: 19bd2ff135befe0b3d5212f9b72b76a8db310df77b1d27eb7abb488443078619160bb6bc60af12a6ade697475855e8db265796676555c578830580170d24578d
|
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
# Unsubscribe
|
2
|
-
Automatically unsubscribe from emails in Rails.
|
1
|
+
# 📭 Unsubscribe
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
Automatically unsubscribe from emails in Rails.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
## 🚀 Installation
|
6
8
|
|
7
|
-
## Installation
|
8
9
|
Add this line to your application's Gemfile:
|
9
10
|
|
10
11
|
```ruby
|
@@ -21,8 +22,112 @@ Or install it yourself as:
|
|
21
22
|
$ gem install unsubscribe
|
22
23
|
```
|
23
24
|
|
24
|
-
|
25
|
-
|
25
|
+
Then run the installation commands:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
rails g unsubscribe:install
|
29
|
+
rails unsubscribe:install:migrations
|
30
|
+
rails db:migrate
|
31
|
+
```
|
32
|
+
|
33
|
+
## 📚 Usage
|
34
|
+
|
35
|
+
### Unsubscribe::Owner
|
36
|
+
|
37
|
+
- Add `include Unsubscribe::Owner` to a `Model`. The `Model` must have an `email` column.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class User < ApplicationRecord
|
41
|
+
include Unsubscribe::Owner
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
#### Available Methods
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
User.first.subscribed_to_mailer? "MarketingMailer"
|
49
|
+
# => true/false
|
50
|
+
|
51
|
+
User.first.to_sgid_for_mailer_subscription
|
52
|
+
# => #<SignedGlobalID:123 ...>
|
53
|
+
```
|
54
|
+
|
55
|
+
### Unsubscribe::Mailer
|
56
|
+
|
57
|
+
- Add `include Unsubscribe::Mailer` to a `Mailer`.
|
58
|
+
- Optionally call `unsubscribe_settings` to set a `name` and `description`. This will be used in the unsubscribe page.
|
59
|
+
- Set `mail to:` to `@recipient.email`. The `@recipient` is an instance of whatever Class `include Unsubscribe::Owner` was added to.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
class MarketingMailer < ApplicationMailer
|
63
|
+
include Unsubscribe::Mailer
|
64
|
+
|
65
|
+
unsubscribe_settings name: "Marketing Emails", description: "Updates on promotions and sales."
|
66
|
+
|
67
|
+
def promotion
|
68
|
+
mail to: @recipient.email
|
69
|
+
end
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
- Call the `Mailer` with a `recipient` parameter.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
MarketingMailer.with(
|
77
|
+
recipient: User.first
|
78
|
+
).promotion.deliver_now
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Available Methods
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
Unsubscribe::MailerSubscription.first.action
|
85
|
+
# => "Unsubscribe from"/"Subscribe to"
|
86
|
+
|
87
|
+
Unsubscribe::MailerSubscription.first.call_to_action
|
88
|
+
# => "Unsubscribe from Marketing Emails"/"Subscribe to Marketing Emails"
|
89
|
+
|
90
|
+
Unsubscribe::MailerSubscription.first.description
|
91
|
+
# => "Updates on promotions and sales."
|
92
|
+
|
93
|
+
Unsubscribe::MailerSubscription.first.name
|
94
|
+
# => "Marketing Emails"
|
95
|
+
```
|
96
|
+
|
97
|
+
### Unsubscribe Link
|
98
|
+
|
99
|
+
- Add the `@unsubscribe_url` link to the `Mailer`.
|
100
|
+
|
101
|
+
```html+erb
|
102
|
+
<%= link_to "Unsubscribe", @unsubscribe_url %>
|
103
|
+
```
|
104
|
+
|
105
|
+
## ⚙️ Customize Templates
|
106
|
+
|
107
|
+
Run `rails g unsubscribe:views` if you want to modify the existing templates.
|
108
|
+
|
109
|
+
## 🌐 I18n
|
110
|
+
|
111
|
+
The language used for `Unsubscribe::MailerSubscription#action` can be translated.
|
112
|
+
|
113
|
+
```yml
|
114
|
+
# config/locales/en.yml
|
115
|
+
en:
|
116
|
+
unsubscribe:
|
117
|
+
action:
|
118
|
+
subscribe: "Subscribe to"
|
119
|
+
unsubscribe: "Unsubscribe from"
|
120
|
+
```
|
121
|
+
|
122
|
+
## 🙏 Contributing
|
123
|
+
|
124
|
+
If you'd like to open a PR please make sure the following things pass:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
bin/rails test
|
128
|
+
bundle exec standardrb
|
129
|
+
```
|
130
|
+
|
131
|
+
## 📜 License
|
26
132
|
|
27
|
-
## License
|
28
133
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
require_dependency "unsubscribe/application_controller"
|
2
|
+
|
3
|
+
module Unsubscribe
|
4
|
+
class MailerSubscriptionsController < ApplicationController
|
5
|
+
before_action :set_owner, only: [:show, :create, :update]
|
6
|
+
before_action :set_mailer, only: [:show]
|
7
|
+
|
8
|
+
def show
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
@mailer = Unsubscribe::MailerSubscription.new(mailer_subscription_params)
|
13
|
+
|
14
|
+
if @owner != @mailer.owner
|
15
|
+
redirect_to(
|
16
|
+
mailer_subscription_path(@owner.to_sgid_for_mailer_subscription, mailer: params[:mailer_subscription][:mailer]),
|
17
|
+
alert: "You are not authorized to perform this action."
|
18
|
+
) and return
|
19
|
+
end
|
20
|
+
|
21
|
+
if @mailer.save
|
22
|
+
redirect_to(
|
23
|
+
mailer_subscription_path(@owner.to_sgid_for_mailer_subscription, mailer: params[:mailer_subscription][:mailer]),
|
24
|
+
notice: "Settings updated."
|
25
|
+
)
|
26
|
+
else
|
27
|
+
redirect_to(
|
28
|
+
mailer_subscription_path(@owner.to_sgid_for_mailer_subscription, mailer: params[:mailer_subscription][:mailer]),
|
29
|
+
alert: @mailer.errors.full_messages.to_sentence
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def update
|
35
|
+
@mailer = Unsubscribe::MailerSubscription.find(params[:mailer_subscription_id])
|
36
|
+
|
37
|
+
if @owner != @mailer.owner
|
38
|
+
redirect_to(
|
39
|
+
mailer_subscription_path(@owner.to_sgid_for_mailer_subscription, mailer: @mailer.mailer),
|
40
|
+
alert: "You are not authorized to perform this action."
|
41
|
+
) and return
|
42
|
+
end
|
43
|
+
|
44
|
+
if @mailer.toggle!(:subscribed)
|
45
|
+
redirect_to mailer_subscription_path(@owner.to_sgid_for_mailer_subscription, mailer: @mailer.mailer), notice: "Settings updated."
|
46
|
+
else
|
47
|
+
redirect_to mailer_subscription_path(@owner.to_sgid_for_mailer_subscription, mailer: @mailer.mailer), alert: @mailer.errors.full_messages.to_sentence
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def set_owner
|
54
|
+
@owner = GlobalID::Locator.locate_signed(params[:id], for: :mailer_subscription)
|
55
|
+
raise ActiveRecord::RecordNotFound if @owner.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_mailer
|
59
|
+
@mailer = @owner.mailer_subscriptions.find_or_initialize_by(mailer: params[:mailer])
|
60
|
+
end
|
61
|
+
|
62
|
+
def mailer_subscription_params
|
63
|
+
params.require(:mailer_subscription).permit(:owner_id, :owner_type, :subscribed, :mailer)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Unsubscribe
|
2
|
+
class MailerSubscription < ApplicationRecord
|
3
|
+
belongs_to :owner, polymorphic: true
|
4
|
+
|
5
|
+
validates :subscribed, inclusion: [true, false], allow_nil: true
|
6
|
+
validates :mailer, presence: true
|
7
|
+
validates :owner_id, uniqueness: {scope: [:mailer, :owner_type]}
|
8
|
+
validate :mailer_should_exist
|
9
|
+
|
10
|
+
def action
|
11
|
+
case subscribed
|
12
|
+
when nil
|
13
|
+
I18n.t("unsubscribe.action.unsubscribe")
|
14
|
+
else
|
15
|
+
subscribed? ? I18n.t("unsubscribe.action.unsubscribe") : I18n.t("unsubscribe.action.subscribe")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def call_to_action
|
20
|
+
"#{action} #{name}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def description
|
24
|
+
details[:description]
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
details[:name].present? ? details[:name] : mailer
|
29
|
+
end
|
30
|
+
|
31
|
+
def details
|
32
|
+
mailer.constantize.unsubscribe_settings
|
33
|
+
rescue NoMethodError
|
34
|
+
raise Unsubscribe::Error, "Make sure to include Unsubscribe::Mailer in #{mailer}"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def mailer_should_exist
|
40
|
+
errors.add(:mailer, "is not a enbled") unless mailer.constantize.enabled
|
41
|
+
rescue NameError
|
42
|
+
errors.add(:mailer, "is not a Mailer")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<h1><%= @mailer.name %></h1>
|
2
|
+
<p><%= @mailer.description %></p>
|
3
|
+
<% if @mailer.new_record? %>
|
4
|
+
<%= button_to(
|
5
|
+
@mailer.call_to_action,
|
6
|
+
mailer_subscriptions_path,
|
7
|
+
params: {
|
8
|
+
id: @owner.to_sgid_for_mailer_subscription,
|
9
|
+
mailer_subscription: {
|
10
|
+
owner_id: @owner.id,
|
11
|
+
owner_type: @owner.class,
|
12
|
+
subscribed: false,
|
13
|
+
mailer: @mailer.mailer
|
14
|
+
}
|
15
|
+
}
|
16
|
+
) %>
|
17
|
+
<% else %>
|
18
|
+
<%= button_to(
|
19
|
+
@mailer.call_to_action,
|
20
|
+
mailer_subscription_path(@owner.to_sgid_for_mailer_subscription),
|
21
|
+
method: :put,
|
22
|
+
params: {
|
23
|
+
mailer_subscription_id: @mailer.id
|
24
|
+
}
|
25
|
+
) %>
|
26
|
+
<% end %>
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateUnsubscribeMailerSubscriptions < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
create_table :unsubscribe_mailer_subscriptions do |t|
|
4
|
+
# Needs to be polymorphic to be flexible. Owner may not always be a User.
|
5
|
+
t.references :owner, polymorphic: true, null: false, index: { name: "unsubscribe_owner_index" }
|
6
|
+
t.boolean :subscribed
|
7
|
+
t.string :mailer, null: false
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
# An owner should only have one Unsubscribe::MailerSubscription record per Mailer.
|
13
|
+
add_index :unsubscribe_mailer_subscriptions, [:owner_id, :owner_type, :mailer], unique: true, name: "unsubscribe_owner_mailer_index"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Unsubscribe
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("./../../../../../", __FILE__)
|
7
|
+
|
8
|
+
def link_manifest_js
|
9
|
+
inject_into_file "app/assets/config/manifest.js" do
|
10
|
+
<<~EOF
|
11
|
+
\n//= link unsubscribe_manifest.js
|
12
|
+
EOF
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def mount_engine
|
17
|
+
inject_into_file "config/routes.rb", after: "Rails.application.routes.draw do" do
|
18
|
+
<<~EOF
|
19
|
+
\n\tmount Unsubscribe::Engine => "/unsubscribe"
|
20
|
+
EOF
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Unsubscribe
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("./../../../../../", __FILE__)
|
7
|
+
|
8
|
+
def copy_views
|
9
|
+
directory "app/views/unsubscribe", "app/views/unsubscribe"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Unsubscribe
|
2
|
+
module Mailer
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_recipient
|
7
|
+
before_action :set_unsubscribe_url, if: :should_unsubscribe?
|
8
|
+
before_action :set_headers, if: :should_unsubscribe?
|
9
|
+
after_action :prevent_delivery_if_recipient_opted_out, if: :should_unsubscribe?
|
10
|
+
end
|
11
|
+
|
12
|
+
class_methods do
|
13
|
+
def unsubscribe_settings(name: nil, description: nil)
|
14
|
+
cattr_accessor :unsubscribe_settings, default: {name: name, description: description}
|
15
|
+
cattr_accessor :enabled, default: true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def prevent_delivery_if_recipient_opted_out
|
22
|
+
mail.perform_deliveries = @recipient.subscribed_to_mailer? self.class.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_recipient
|
26
|
+
@recipient = params[:recipient]
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_unsubscribe_url
|
30
|
+
@unsubscribe_url = unsubscribe.mailer_subscription_url(@recipient.to_sgid_for_mailer_subscription, mailer: self.class)
|
31
|
+
end
|
32
|
+
|
33
|
+
def should_unsubscribe?
|
34
|
+
@recipient.present? && @recipient.respond_to?(:subscribed_to_mailer?)
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_headers
|
38
|
+
headers["List-Unsubscribe"] = "<#{@unsubscribe_url}>"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Unsubscribe
|
2
|
+
module Owner
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :mailer_subscriptions, class_name: "Unsubscribe::MailerSubscription", as: :owner, inverse_of: :owner, dependent: :destroy
|
7
|
+
end
|
8
|
+
|
9
|
+
def subscribed_to_mailer?(mailer)
|
10
|
+
Unsubscribe::MailerSubscription.find_by(
|
11
|
+
owner: self,
|
12
|
+
mailer: mailer,
|
13
|
+
subscribed: false
|
14
|
+
).nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_sgid_for_mailer_subscription
|
18
|
+
to_sgid(for: :mailer_subscription)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/unsubscribe/version.rb
CHANGED
data/lib/unsubscribe.rb
CHANGED
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unsubscribe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 1.0.0.alpha.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Polito
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 6.1.4
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version: 6.
|
19
|
+
version: 6.0.0
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 6.1.4
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version: 6.
|
26
|
+
version: 6.0.0
|
33
27
|
description: 'Automatically unsubscribe from emails in Rails. '
|
34
28
|
email:
|
35
29
|
- stevepolito@hey.com
|
@@ -42,16 +36,28 @@ files:
|
|
42
36
|
- Rakefile
|
43
37
|
- app/assets/config/unsubscribe_manifest.js
|
44
38
|
- app/assets/stylesheets/unsubscribe/application.css
|
39
|
+
- app/assets/stylesheets/unsubscribe/mailer_subscriptions.css
|
45
40
|
- app/controllers/unsubscribe/application_controller.rb
|
41
|
+
- app/controllers/unsubscribe/mailer_subscriptions_controller.rb
|
46
42
|
- app/helpers/unsubscribe/application_helper.rb
|
43
|
+
- app/helpers/unsubscribe/mailer_subscriptions_helper.rb
|
47
44
|
- app/jobs/unsubscribe/application_job.rb
|
48
45
|
- app/mailers/unsubscribe/application_mailer.rb
|
49
46
|
- app/models/unsubscribe/application_record.rb
|
47
|
+
- app/models/unsubscribe/mailer_subscription.rb
|
50
48
|
- app/views/layouts/unsubscribe/application.html.erb
|
49
|
+
- app/views/unsubscribe/mailer_subscriptions/show.html.erb
|
50
|
+
- config/locales/en.yml
|
51
51
|
- config/routes.rb
|
52
|
+
- db/migrate/20210918092925_create_unsubscribe_mailer_subscriptions.rb
|
53
|
+
- lib/generators/unsubscribe/install/install_generator.rb
|
54
|
+
- lib/generators/unsubscribe/views/views_generator.rb
|
52
55
|
- lib/tasks/unsubscribe_tasks.rake
|
53
56
|
- lib/unsubscribe.rb
|
54
57
|
- lib/unsubscribe/engine.rb
|
58
|
+
- lib/unsubscribe/error.rb
|
59
|
+
- lib/unsubscribe/mailer.rb
|
60
|
+
- lib/unsubscribe/owner.rb
|
55
61
|
- lib/unsubscribe/version.rb
|
56
62
|
homepage: https://github.com/stevepolitodesign/unsubscribe
|
57
63
|
licenses:
|
@@ -71,9 +77,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
77
|
version: '0'
|
72
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
79
|
requirements:
|
74
|
-
- - "
|
80
|
+
- - ">"
|
75
81
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
82
|
+
version: 1.3.1
|
77
83
|
requirements: []
|
78
84
|
rubygems_version: 3.1.2
|
79
85
|
signing_key:
|